看过《阿里Java开发手册》的你,应该知道
线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
上图
ThreadPoolExecutor机制
核心构造方法讲解
下面是ThreadPoolExecutor最核心的构造方法参数:
1)corePoolSize
核心线程池的大小
2)maximumPoolSize
最大线程池大小
3)keepAliveTime
线程池中超过corePoolSize
数目的空闲线程最大存活时间;可以allowCoreThreadTimeOut(true)
使得核心线程超出有效时间也关闭
4)TimeUnit
keepAliveTime
的时间单位
5)workQueue
阻塞任务队列
6)threadFactory
新建线程工厂
7)RejectedExecutionHandler
当提交任务数超过maximumPoolSize+workQueue
之和时,任务会交给RejectedExecutionHandler
来处理
重点讲解
corePoolSize
,maximumPoolSize
,workQueue
三者之间的关系
1)当线程池小于corePoolSize
时,新提交的任务会创建一个新线程执行任务,即使线程池中仍有空闲线程。
2)当线程池达到corePoolSize
时,新提交的任务将被放在workQueue
中,等待线程池中的任务执行完毕
3)当workQueue
满了,并且maximumPoolSize > corePoolSize
时,新提交任务会创建新的线程执行任务
4)当提交任务数超过maximumPoolSize
,新任务就交给RejectedExecutionHandler
来处理
5)当线程池中超过 corePoolSize
线程,空闲时间达到keepAliveTime
时,关闭空闲线程
6)当设置allowCoreThreadTimeOut(true)
时,线程池中corePoolSize
线程空闲时间达到keepAliveTime
也将关闭
为什么上面不允许使用Executors工厂类,要自己定义呢?
1)创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池就会补充一个新的线程。
配置的corePoolSize
和maximumPoolSize
大小相同,同时使用一个无界LinkedBlockingQueue
存放阻塞任务,因此多余的任务将存在再阻塞队列,不会由RejectedExecutionHandler
来处理。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
2)创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是说相当于单线程串行执行所有任务。如果这个唯一的线程因为异常而结束,那么会新建一个线程来替换。
此线程池保证所有的任务的执行顺序按照任务的提交顺序执行。配置corePoolSize = maximumPoolSize = 1
,无界阻塞队列LinkedBlockingQueue
;保证任务有一个线程串行执行
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
3)创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒)不执行任务的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。
此线程池不会对线程池的大小做限制,线程池的大小完全依赖于操作系统(或者JVM)能够创建的最大线程大小。配置corePoolSize = 0
maximumPoolSize = Integer.MAX_VALUE
keepAliveTime = 60s
,以及一个无容量的阻塞队列SynchronousQueue
,因此任务提交之后,将会创建新的线程执行;线程空闲超过60s就会销毁
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
4)构造有定时功能的线程池,配置corePoolSize
,无界延迟阻塞队列DelayedWorkQueue
;有意思的是:maximumPoolSize = Integer.MAX_VALUE
,由于DelayedWorkQueue
是无界的,所以这个值是没有意义的。
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1));
}