当100个任务同时请求提交任务,线程池时如何工作的
问题
如果100个任务同时往线程池(最小线程5,最大线程10,队列时LinkedBlockingDeque)提交,线程池会发生什么?线程池如何处理这些任务?
线程池
我们首先来看看线程池的工作流程。
当线程池被创建成功后,其中是没有任何一个线程的。任务队列是作为线程池的一个构造参数传入的,如果初始队列中有任务,线程池也并不会马上执行其中的任务。
如图所示,当应用通过execute方法往线程池提交任务时,线程池会做出如下的动作:
1、如果正在运行的线程数小于核心线程数时(corePoolSize),通过addWorker方法创建新线程,并将此任务作为当前线程的初始任务执行
2、如果当前运行的线程数量大于或者等于核心线程数时,addWorker会return false,这时,将任务放入队列
- 如果队列满了,通过addWorker创建非核心线程,并立即将任务执行
- 如果队列满了,通过addWorker创建非核心线程失败,则通过reject方法执行失败策略
如果一个工作线程长时间无事可做,超过keepAliveTime参数设置的超时时间,如果当前运行的线程数大于核心线程数,这个线程便会执行停止策略。
那么其是如何实现的呢?
while (task != null || (task = getTask()) != null) {
...
}
在getTask()方法中
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
其实利用的是阻塞队列poll方法的超时时间,当达到超时时间,仍然没有获取到任务,便会返回null,进而Worker中的while循环跳出,结束线程。
问题解答
回到问题本身,当100个请求同时执行execute方法往线程池提交任务时,
- 由于一开始工作线程数是小于核心线程的,这100个任务会通过CAS争抢的方式创建新核心线程(worker),立即执行任务
- 如果核心线程数达到5,将任务放入队列中
- 如果放入成功,调用addWorker创建工作线程,从队列中取任务执行(工作线程数大于等于10时,会创建失败,导致任务堆积在队列中,等待其他工作线程执行)
- 如果放入失败,addWorker创建工作线程,立即执行该任务,如果创建失败,抛出异常
扩展
线程池参数的设置策略
线程数
一般根据业务时IO密集型还是计算密集型
- 如果时计算密集型,那么一般根据设置成CPU核心数,防止过多线程,导致上下文切换,降低运行效率
- 如果时IO密集型,考虑到充分压榨CPU的计算能力,可以设置为2倍CPU核心数,具体根据业务情况而定
超时时间
根据每一个任务执行所需的时间而定,避免频繁创建和销毁线程,提高线程利用率。