概述
worker 线程会从阻塞队列中获取需要执行的任务,这个方法不是简单的 take 数据,我们来
分析下他的源码实现
你也许好奇是怎样判断线程有多久没有活动了,是不是以为线程池会启动一个监控线程,专
门监控哪个线程正在偷懒?想太多,其实只是在线程从工作队列 poll 任务时,加上了超时
限制,如果线程在 keepAliveTime 的时间内 poll 不到任务,那我就认为这条线程没事做,
可以干掉了
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {//自旋
int c = ctl.get();
int rs = runStateOf(c);
/** 对线程池状态的判断,两种情况会 workerCount-1,并且返回 null
1. 线程池状态为 shutdown,且 workQueue 为空(反映了 shutdown 状态的线程池还是
要执行 workQueue 中剩余的任务的)
2. 线程池状态为 stop(shutdownNow()会导致变成 STOP)(此时不用考虑 workQueue
的情况)
**/
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;;//返回 null,则当前 worker 线程会退出
}
int wc = workerCountOf(c);
// timed 变量用于判断是否需要进行超时控制。
// allowCoreThreadTimeOut 默认是 false,也就是核心线程不允许进行超时;
// wc > corePoolSize,表示当前线程池中的线程数量大于核心线程数量;
// 对于超过核心线程数量的这些线程,需要进行超时控制
// Are workers subject to culling?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
/**
1. 线程数量超过 maximumPoolSize 可能是线程池在运行时被调用了 setMaximumPoolSize()
被改变了大小,否则已经 addWorker()成功不会超过 maximumPoolSize
2. timed && timedOut 如果为 true,表示当前操作需要进行超时控制,并且上次从阻塞队列中
获取任务发生了超时.其实就是体现了空闲线程的存活时间
第一次进来时候,timed && timedOut 为false,直接跳过此次if,如果大于核心线程,
则所有线程自旋都会执行下面的workQueue.poll,不需要此线程是核心线程,还是非核心线程。
如果超时获取的为null,则在下次自旋时候,通过原子的减法操作,如果减法失败,则进行下一次自
旋,如果减法成功,则释放线程
**/
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
// 原子操作,只有当减法成功时候,才会释放线程。
return null;
continue;
}
try {
/**
根据 timed 来判断,如果为 true,则通过阻塞队列 poll 方法进行超时控制,如果在
keepaliveTime 时间内没有获取到任务,则返回 null.
否则通过 take 方法阻塞式获取队列中的任务
**/
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null) //如果拿到的任务不为空,则直接返回给 worker 进行处理
return r;
timedOut = true;// 如果 r==null,说明已经超时了,队列中仍然没有任务,此时设置timedOut=true,在下次自旋的时候进行回收
} catch (InterruptedException retry) {
// 如果获取任务时当前线程发生了中断,则设置 timedOut 为false 并返回循环重试
timedOut = false;
}
}
}
这里重要的地方是第二个 if 判断,目的是控制线程池的有效线程数量。由上文中的分析可以
知道,在执行 execute 方法时,如果当前线程池的线程数量超过了 corePoolSize 且小于
maximumPoolSize,并且 workQueue 已满时,则可以增加工作线程,但这时如果超时没有
获取到任务,也就是 timedOut 为 true 的情况,说明 workQueue 已经为空了,也就说明了
当前线程池中不需要那么多线程来执行任务了,可以把多于 corePoolSize 数量的线程销毁
掉,保持线程数量在 corePoolSize 即可。
什么时候会销毁?当然是 runWorker 方法执行完之后,也就是 Worker 中的 run 方法执行
完,由 JVM 自动回收。
getTask 方法返回 null 时,在 runWorker 方法中会跳出 while 循环,然后会执行
processWorkerExit 方法
- processWorkerExit
runWorker 的 while 循环执行完毕以后,在 finally 中会调用 processWorkerExit,来销毁工作线
程
最后
以上就是舒服微笑为你收集整理的线程池中的线程是如何超时自动销毁的?的全部内容,希望文章能够帮你解决线程池中的线程是如何超时自动销毁的?所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复