最近项目中使用到了线程池,习惯使用newCachedThreadPool创建,但是一直不是很明确Executors类下四种创建线程池的区别,经走访学习后,总结一下。
**注意:以下内容中 Integer.MAX_VALUE描述为无限大方便观看**
1. newFixedThreadPool(int cnt)
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
此方法是创建一个固定核心数线程池,以及LinkedBlockingQueue队列,其大小为无限大。
也就说如果创建该线程池时,指定参数为10,那么就会在池中创建10个核心线程,以及一个无限大的LinkedBlockingQueue。
最大同时执行数为10,等待数无限大。
2. newCachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
此方法是创建了一个核心线程数为0,但是临时线程无限大(60秒)的池,该等待队列类为SynchronousQueue,与其称为队列,不如叫一个点,如果该点中存在一个元素,那么插入该点的线程将被阻塞,直到点上的元素被消费。看似无意义(其实本人理解也无意义…),实则为了工厂参数的一致性做出的类似于妥协?(求大神科普)
3. newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
此方法是创建了仅有一个核心线程的线程池,无临时线程数,使用无限大的LinkedBlockingQueue数组作为队列。
一个线程的线程池有什么意义呢?
其实我理解的此线程池的意义就是直接体现了线程的复用性,且配合无限大的队列,执行一些不那么重要且必须执行的特殊任务。(如果每次任务时间长,还使用这种池不就等于守护线程循环执行吗?)
4. 问题发现
极端条件下:
newFixedThreadPool 中创建无线大的队列
newCachedThreadPool 创建无限大的线程数
newSingleThreadExecutor 不说了
极端条件下,怎么办呢?
5. 自定义线程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
10, 20,
60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100));
解释:
参数一:10条核心线程
参数二:20最大线程数
参数三:临时线程存活时间 60
参数四:参数三的单位 秒
参数五:队列类(LinkedBlockingQueue)长度100
6. 执行线程优先级的研究
调度优先级:核心线程 > 队列 > 临时线程
也就说,execute执行线程时,首先查看核心线程有无空闲线程,如果有则addWorker,如果没有,则加入队列,队列满则加入临时线程。
执行优先级:核心线程 > 临时线程 > 队列
7. newScheduledThreadPool(int cnt)定时任务线程池
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
参数为核心线程数,临时线程无限大,并且临时线程结束后立刻销毁,
用DelayedWorkQueue作为队列类(因定时任务部分需要延时特殊性,需要此特殊的优先级队列,根据延时时间优先执行任务)