「这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战」。
4、工作线程如何从队列中获得任务
线程从任务队列中获取任务然后执行,执行完任务的空闲线程会再次去从队列中申请任务再去执行。这部分策略由getTask方法实现,其执行流程如下图所示:
getTask这部分进行了多次判断,为的是控制线程的数量,使其符合线程池的状态。工作线程Worker会不断接收新任务去执行,而当工作线程Worker接收不到任务的时候,则会返回null值,表示线程池现在不应该持有那么多线程,在runWorker方法中就会调用processWorkerExit方法进行线程回收。遇到下列情况,worker必须退出:
- 由于调用setMaximumPoolSize,worker数量超过了maximumPoolSize;
- 线程池已经停止;
- 线程池被shutdown且队列为空;
- worker等待任务超时,要被销毁 下面是代码分析:
private Runnable getTask() {
// 上一个poll调用是否超时标记
boolean timedOut = false;
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// SHUTDOWN时会继续处理队列任务,如果队列为空,则需要销毁线程
// STOP及以后状态,不允许处理队列中任务,也需要销毁线程
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
// 返回null,表示要销毁线程
return null;
}
// 获取线程数量
int wc = workerCountOf(c);
// allowCoreThreadTimeOut默认为false,使核心线程即使空闲也保持活跃,如果为true,核心线程使用keepAliveTime参数来超时等待任务
// 1.1 worker数量小于等于corePoolSize,timed为false
// 2.1 worker数量大于corePoolSize,timed为true
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 1.2 worker数量小于等于corePoolSize,则一定小于maximumPoolSize,跳过执行以下逻辑
// 2.2 worker数量大于maximumPoolSize,则一定大于corePoolSize,timed为true,条件(wc > maximumPoolSize || (timed && timedOut))成立;
// maxmumPoolSize最小值可设置为1,条件(wc > 1 || workQueue.isEmpty())也成立,所以返回null,表示要销毁当前worker
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
// 1.3 timed为false,执行workQueue.take(),阻塞等待,直到获取元素
// 2.3 timed为true,等待keepAliveTime时间后返回,r为null即队列此时为空,线程处于空闲状态,timedOut为true,再次循环,执行到2.2处就会返回null,表示销毁当前线程
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
5、如何销毁Worker?
Worker线程的run方法内部调用runWorker方法,内部有一个while循环,循环条件成立时,run方法无法退出,就能保证Worker一直活跃;while循环条件被打破,run方法就会退出,执行完run方法,线程就要走向死亡。在run方法快要结束时,调用processWorkerExit方法进行一些清理工作,主要内容包括:
- 把自己从工人集合中移除;
- 可能尝试终结线程池;
- 如果少于corePoolSize的工人在运行,或者当前工人由于用户的代码异常而退出,或者队列非空但是没有工人,都会生成一个工人替换当前工人;
/**
* 该方法由工作者线程调用
*
* @param w the worker
* @param completedAbruptly worker是否由于用户代码的异常而死亡
*/
private void processWorkerExit(Worker w, boolean completedAbruptly) {
// 用户代码异常,completedAbruptly为true
if (completedAbruptly)
// 减少工人数量
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 完成任务计数器,只在工人线程终结的时候修改
completedTaskCount += w.completedTasks;
// 从HashSet中移除
workers.remove(w);
} finally {
mainLock.unlock();
}
// 尝试终结线程池
tryTerminate();
// 1、因为用户异常导致worker终结,新增worker;
// 2、RUNNING或者SHUTDOWN状态,低于corePoolSize的worker在运行或者队列非空工人为0,新增worker
int c = ctl.get();
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
return; // replacement not needed
}
addWorker(null, false);
}
}
final void tryTerminate() {
for (;;) {
int c = ctl.get();
// 正在运行,不能终结;
// TIDYING状态,worker已全部被终结,不用终结;
// SHUTDOWN状态,队列不为空,还有任务要处理,不能终结;
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
if (workerCountOf(c) != 0) {
// 中断至多一个空闲(等待任务)的线程
interruptIdleWorkers(ONLY_ONE);
return;
}
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 设置线程池状态为TIDYING,worker数量为0
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
// 子类实现的方法
terminated();
} finally {
// 线程池状态设置为TERMINATED,worker数量置为0
ctl.set(ctlOf(TERMINATED, 0));
// 唤醒因调用awaitTermination方法而阻塞的线程
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
// 设置失败时,循环重试
}
}