线程池 Worker 生命周期
Worker 生命周期
线程池的5种状态
// Integer.SIZE 为 32 COUNT_BITS = 29
private static final int COUNT_BITS = Integer.SIZE - 3;
// 前三位0,后29位都为1
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// 线程池运行状态
// 前三位 111,后29位都是0,第一位为1表示负数
private static final int RUNNING = -1 << COUNT_BITS;
// 32 为都为 0
// SHUTDOWN: Don't accept new tasks, but process queued tasks
private static final int SHUTDOWN = 0 << COUNT_BITS;
// 前三位 001,后29位都为0
// STOP: Don't accept new tasks, don't process queued tasks, and interrupt in-progress tasks
private static final int STOP = 1 << COUNT_BITS;
// 前三位 010,后29位都是0
// TIDYING: All tasks have terminated, workerCount is zero, the thread transitioning to state TIDYING will run the terminated() hook method
private static final int TIDYING = 2 << COUNT_BITS;
// 前三位 011,后29位都是0
// TERMINATED: terminated() has completed
private static final int TERMINATED = 3 << COUNT_BITS;
// & 位与运算符 两位都为1,结果才为1
// ~CAPACITY 前三位1 后面29位为0
private static int runStateOf(int c) { return c & ~CAPACITY; }
private static int workerCountOf(int c) { return c & CAPACITY; }
// | 位或运算符,两个位都为0,结果才为0
private static int ctlOf(int rs, int wc) { return rs | wc; }
Worker 添加
Worker 添加的执行逻辑在 execute(Runnable command)
函数中
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true)) return;
}
如果 Worker 数量小于核心线程数量,则直接添加。
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
如果线程池处于 RUNNING
状态并且添加任务到 workQueue 成功,然后重新检查线程池状态如果状态改变,并且移除任务成功则走饱和策略。如果线程池装备没变,或者改变了但是移除任务不成功,并且线程池中 Worker 数量为 0,则添加一个空任务的 Worker,让队列中的任务继续执行。
public void execute(Runnable command) {
if (command == null) throw new NullPointerException();
int c = ctl.get();
// 小于 corePoolSize 直接添加
if (workerCountOf(c) < corePoolSize) {
// 添加成功直接返回
if (addWorker(command, true))return;
c = ctl.get();
}
// 处于 Running 状态并且添加 workQueue 成功
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
// 不在 Running 状态并且移除任务成功,则走饱和策略
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0) // Worker 数量为0,添加一个空任务的 Worker,使添加到 workQueue 的任务能够被执行
addWorker(null, false);
} else if (!addWorker(command, false)) // workQueue 满了(不在 Runing 状态是无法添加有任务的 Worker 的)
reject(command);
}
// rs > SHUTDOWN
// || (rs == SHUTDOWN && firstTask != null)
// || (rs == SHUTDOWN && workQueue.isEmpty()) 如果 workQueue 不空,即使是 SHUTDOWN 状态也可以创建 Worker
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty())) return false;
任务获取
在解析 Worker 执行之前先得了解任务获取,下面是 getTask()
函数解析:
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
判断线程池状态,如果是 >= STOP
或者是 SHUTDOWN
状态并且任务队列为空,Worker 数量减一,并返回 null
。
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c)) return null;
continue;
}
allowCoreThreadTimeOut
为false
表示核心线程是闲置的也不会被回收,true
表示如果等待任务时间过长也会被回收。timed
表示如果核心线程可以回收或者总线程数大于核心线程数,那么获取任务时会设置超时时间。timedOut
表示获取任务时是否超时。
try {
Runnable r = timed ? workQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS) : workQueue.take();
if (r != null) return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
如果成功获取任务则返回,如果超时则设置 timedOut = true
,如果阻塞队列响应线程中断,则设置 timedOut = false
。
Worker 执行
Worker 执行的主要内容在 runWorker(Worker w)
函数中,下面是具体解析:
w.unlock(); // allow interrupts
这行代码用来表明该线程时可以被中断的,首先 Worker 继承了 AQS,并且在构造函数中调用了 setState(-1)
用于禁止中断,同时要想中断 Worker 有两种方式,一种是 tryLock()
(通过 CAS 方式把 state
从 0 设置为 1) 然后调用 interrupt()
,一种是判断 getState() >= 0
然后调用 interrupt()
,而 unlock()
作用就是把 state
设置为 0,使得可以被中断。
while (task != null || (task = getTask()) != null) {
w.lock();
// 执行任务
w.unlock();
}
用来从任务队列中获取新任务,并且在执行任务时加锁。这里加锁的目的是表明该 Worker 不是闲置的 Worker,因为闲置的 Worker 可能会被回收。
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() && runStateAtLeast(ctl.get(), STOP)))
&& !wt.isInterrupted())
wt.interrupt();
- 如果线程池状态是
>= STOP
并且线程没有中断,那么调用线程中断 - 如果线程池状态是
< STOP
,那么清除中断标志,如果线程之前不是中断状态,则继续执行;如果线程之前是中断状态,那么会判断线程池状态是否是>= STOP
,如果是,调用线程中断,否则继续执行。
你可能会问什么情况下会发生:线程解除中断状态并且线程池状态会从< STOP
,变成>= STOP
?假如线程池突然调用了shutdownNow()
可能会发生上面的情况,作用是为了在调用shutdownNow()
的时候立即中断线程。
beforeExecute(wt, task);
try{
task.run();
} finally {
afterExecute(task, thrown);
}
beforeExecute()
,afterExecute()
分别是任务执行前和执行后的调用,可以用来做监控。
Worker 回收
Worker 回收的主要执行逻辑在 processWorkerExit
中
processWorkerExit(Worker w, boolean completedAbruptly){
// completedAbruptly 为 true 代表是任务异常导致的
if (completedAbruptly) decrementWorkerCount();
completedTaskCount += w.completedTasks;
// 回收 Worker
workers.remove(w);
if (runStateLessThan(c, STOP)) {
// 如果是正常终止的,并且还有 Worker,则不添加替代 Worker
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty()) min = 1;
if (workerCountOf(c) >= min) return;
}
addWorker(null, false);
}
}
如果在执行 task.run()
出现异常,或者 getTask()
返回 null
就会执行上面的函数。Worker 就会被回收掉。