不积跬步,无以至千里。不积小流,无以成江海。
线程池参数
1 |
|
参数解释
corePoolSize: 核心线程的大小,就算没有任务执行,在不设置 allowCoreThreadTimeOut 的情况下,就会一直存活。
maximumPoolSize: 线程池最大可容纳的线程数,如果线程池中,提交的线程超过了 corePoolSize,还可以继续提交,但是不能超过 maximumPoolSize。
keepAliveTime: 当线程池中的线程数大于核心线程数量时,无用的线程等待任务执行的最大存活的时间。
unit: 时间单位的枚举,标识 keepAliveTime 的时间单位。
workQueue: 管理通过 execute 方法提交的未执行的任务的队列。
threadFactory: 线程池创建线程使用的工厂。
handler: 当线程池达到最大值,且排队的队列满了的时候,就会拒绝新的任务加入时一个处理拒绝加入的回调。
1 |
|
上述示例中创建了一个初始线程数为5,队列容量为5,最大线程数为10,线程数超过5时无用线程最多存活3秒的线程池。
线程池创建方式
Java通过Executors(jdk1.5并发包)来创建4种线程池,虽然方便但并不推荐。本文推荐使用 ThreadPoolExecutor 构造方法来创建线程池。
Executors.newCachedThreadPool(): 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
Executors.newFixedThreadPool(): 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
Executors.newScheduledThreadPool(): 创建一个定长线程池,支持定时及周期性任务执行。
Executors.newSingleThreadExecutor(): 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
线程池执行逻辑
当线程池接受到新任务时会经历以下几个步骤:
1、判断核心线程(corePoolSize)是否已满。(核心线程未满:创建核心线程执行任务,核心线程已满进入下一步。)
2、判断队列线程(workQueue)是否已满。(队列线程未满:将任务添加到队列,队列线程已满进入下一步。)
3、判断线程池(maximumPoolSize)是否已满。(线程池未满:创建非核心线程执行任务,线程池已满:按照策略处理无法执行的任务。)
为什么不推荐通过Executors来创建线程池
在阿里巴巴 Java 开发手册中禁止使用 Executors 来创建线程池。原因如下:
1、newFixedThreadPool 和 newSingleThreadExecutor: 主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至 OOM。
1 |
|
1 |
|
newFixedThreadPool和newSingleThreadExecutor 都创建了一个无界队列 LinkedBlockingQueuesize,是一个最大值为 Integer.MAX_VALUE 的线程阻塞队列,当添加任务的速度大于线程池处理任务的速度,可能会在队列堆积大量的请求,消耗很大的内存,甚至导致 OOM。
2、newCachedThreadPool和newScheduledThreadPool: 主要问题是线程数最大数是 Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至 OOM。
1 |
|
1 |
|
newCachedThreadPool 和 newScheduledThreadPool 创建的线程池允许的最大线程数是 Integer.MAX_VALUE,空闲线程存活时间为0,当添加任务的速度大于线程池处理任务的速度,可能会创建大量的线程,消耗资源,甚至导致 OOM。