首页 > 技术文章 > ThreadPoolExecutor线程池的keepAliveTime

zxporz 2019-05-29 11:24 原文

keepAliveTime含义

看了很多文章觉得都不能把keepAliveTime的意思说的很明白,希望通过自己的理解把keepAliveTime说的明确一些

先引用一句我觉得相对说的比较明白的含义:当线程空闲时间达到keepAliveTime,该线程会退出,有两个疑问:1、线程为什么会空闲 2、线程为什么要退出

如果我们不能把线程池各个参数的来龙去脉都梳理清楚其实是很难明白keepAliveTime的含义的

我们来举例说明:

核心线程数10,最大线程数30,keepAliveTime是3秒

随着任务数量不断上升,线程池会不断的创建线程,直到到达核心线程数10,就不创建线程了,

这时多余的任务通过加入阻塞队列来运行,

当超出阻塞队列长度+核心线程数时,

这时不得不扩大线程个数来满足当前任务的运行,这时就需要创建新的线程了(最大线程数起作用),上限是最大线程数30

那么超出核心线程数10并小于最大线程数30的可能新创建的这20个线程相当于是“借”的,如果这20个线程空闲时间超过keepAliveTime,就会被退出

我们来看开头提到的两个问题:

1、线程为什么会空闲

2、线程为什么要退出

答:

1、没有任务时线程就会空闲下来,在线程池中任务是任务(Runnale)线程是线程(Worker)

2、通常超出核心线程的线程是“借”的,也就是说超出核心线程的情况算是一种能够预见的异常情况,并且这种情况并不常常发生(如果常常发生,那我想你应该调整你的核心线程数了),所以这种不经常发生而创建的线程为了避免资源浪费就应该要退出

我们需要看一下java.util.concurrent.ThreadPoolExecutor#getTask源码来验证上面一段话的含义:

int wc = workerCountOf(c);
// Are workers subject to culling? 是否屠宰workers
//当allowCoreThreadTimeOut为true或者当前任务数超过核心线程数时,timed为true
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
……
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) ://如果timed为true说明worker有可能要被关闭,这里调用的代码含义:如果超过keepAliveTime纳秒还没取到任务,就返回null,后面会调用processWorkerExit把worker关闭
workQueue.take();//否则任务队列为空就阻塞在这里,直到任务队列再有任务
if (r != null)
return r;

10个核心线程会不会退出,由下面的参数决定:

allowCoreThreadTimeout:是否允许核心线程空闲退出,默认值为false

当keepAliveTime设置为0时到底是空闲线程直接退出还是不退出

通过实验证明和上文代码workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)证明,是直接不等待退出,而不是永远不退出

这样我们就需要注意了,这个值设置为0 并不是个很好的做法(除非场景中任务数量极少能超出核心线程数),如果任务数频繁超出核心线程数,这个值需要评估设定为合理值尽量避免线程开启关闭的动作

(上图,如果永远不退出,那么workers就不是10 而是45)

 

推荐阅读