当100个任务同时请求提交任务,线程池时如何工作的

阿飞 2021年06月09日 642次浏览

问题

如果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核心数,具体根据业务情况而定

超时时间

根据每一个任务执行所需的时间而定,避免频繁创建和销毁线程,提高线程利用率。