线程池对线程的管理,核心在于 Worker 内部类 和 ctl 状态控制变量。下面从创建、运行、销毁三个维度拆解。
一、Worker:线程池里的"线程包装器"
线程池并不直接持有 Thread 对象,而是包装成 Worker:
private final class Worker extends AbstractQueuedSynchronizer implements Runnable {
final Thread thread; // 真正干活的线程
Runnable firstTask; // 第一个任务(可能为 null)
volatile long completedTasks; // 已完成任务计数
Worker(Runnable firstTask) {
setState(-1); // AQS 状态:-1 表示禁止中断,直到 runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this); // 创建线程
}
public void run() {
runWorker(this); // 线程启动后进入这里
}
}
Worker 继承 AQS 的巧妙设计
Worker 继承 AbstractQueuedSynchronizer 不是为了排队,而是用 AQS 的状态来实现一个不可重入的互斥锁:
| 状态 | 含义 |
|---|---|
-1 |
初始化中,禁止中断 |
0 |
未加锁(空闲) |
1 |
已加锁(正在执行任务) |
线程池通过 tryLock() 来判断 Worker 是否空闲,从而决定是否中断它。
二、线程创建:addWorker() 方法
当任务提交后,线程池判断需要创建新线程时,调用 addWorker():
private boolean addWorker(Runnable firstTask, boolean core) {
// 1. CAS 尝试增加线程计数(ctl 的低29位)
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c); // 获取运行状态
// 状态检查:如果已 SHUTDOWN 且队列非空,不再创建
if (rs >= SHUTDOWN && !(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c); // 当前线程数
// 容量检查:core 为 true 检查 corePoolSize,否则检查 maximumPoolSize
if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize))
return false;
if (compareAndIncrementWorkerCount(c)) // CAS 增加线程计数
break retry;
c = ctl.get();
if (runStateOf(c) != rs)
continue retry; // 状态变了,重试外层循环
}
}
// 2. 真正创建 Worker 并启动线程
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask); // 创建 Worker(内部创建 Thread)
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 再次检查状态,将 Worker 加入 workers HashSet
workers.add(w);
workerAdded = true;
} finally {
mainLock.lock();
}
if (workerAdded) {
t.start(); // 🚀 启动线程!
workerStarted = true;
}
}
} finally {
if (!workerStarted)
addWorkerFailed(w); // 启动失败,回滚
}
return workerStarted;
}
创建流程图
任务提交
↓
判断需要创建线程
↓
CAS 增加 ctl 线程计数(原子操作)
↓
new Worker(firstTask) → ThreadFactory.newThread(this)
↓
加 mainLock → workers.add(w)
↓
thread.start() → 执行 Worker.run() → runWorker(this)
三、线程运行:runWorker() 方法
线程启动后进入 runWorker(),这是线程的核心生命周期循环:
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // 允许中断(state 从 -1 变为 0)
boolean completedAbruptly = true;
try {
// 🔥 核心循环:先执行 firstTask,然后不断从队列取任务
while (task != null || (task = getTask()) != null) {
w.lock(); // 加锁,标记为"工作中"
// 检查线程池状态,必要时中断自己
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() && runStateAtLeast(ctl.get(), STOP)))
&& !wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task); // 钩子方法,可自定义
Throwable thrown = null;
try {
task.run(); // 🎯 真正执行任务!
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown); // 钩子方法
}
} finally {
task = null;
w.completedTasks++;
w.unlock(); // 解锁,标记为"空闲"
}
}
completedAbruptly = false; // 正常退出循环
} finally {
processWorkerExit(w, completedAbruptly); // 线程退出处理
}
}
关键点
-
while循环 :线程不会执行完一个任务就死,而是循环取任务,实现线程复用 -
getTask():从队列阻塞获取任务,这是线程"保活"或"销毁"的分水岭 -
w.lock()/unlock():通过 AQS 锁标识线程是否在工作,便于shutdown()时区分"空闲线程"和"忙碌线程"
四、线程销毁:核心在 getTask() 和 processWorkerExit()
4.1 getTask():决定线程是等待还是销毁
private Runnable getTask() {
boolean timedOut = false;
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// 1. 线程池状态检查:STOP / SHUTDOWN 且队列为空 → 返回 null,线程销毁
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount(); // 线程计数 -1
return null;
}
int wc = workerCountOf(c);
// 2. 判断是否需要超时回收
// allowCoreThreadTimeOut 默认为 false
// 如果线程数 > corePoolSize,或者允许核心线程超时,则 timed = true
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 3. 回收条件:
// (wc > maximumPoolSize 或 超时) 且 (wc > 1 或 队列为空)
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null; // 返回 null → 线程即将销毁
continue;
}
try {
// 4. 从队列取任务
// timed = true → poll(keepAliveTime) 带超时阻塞
// timed = false → take() 无限阻塞
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true; // 超时了,下次循环可能触发回收
} catch (InterruptedException retry) {
timedOut = false; // 被中断,重试
}
}
}
销毁逻辑图解
runWorker 循环
↓
getTask()
├── 线程池 STOP / (SHUTDOWN 且队列为空)
│ └── return null → processWorkerExit() → 线程销毁
│
├── 线程数 > corePoolSize(或 allowCoreThreadTimeOut=true)
│ └── workQueue.poll(keepAliveTime)
│ ├── 超时未取到 → return null → 销毁
│ └── 取到任务 → 继续执行
│
└── 线程数 ≤ corePoolSize(默认)
└── workQueue.take() → 无限阻塞等待 → 线程保活
4.2 processWorkerExit():线程退出清理
private void processWorkerExit(Worker w, boolean completedAbruptly) {
// 1. 如果是异常退出,线程计数需要补减
if (completedAbruptly)
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks; // 累加完成的任务数
workers.remove(w); // 从 workers 集合移除
} finally {
mainLock.unlock();
}
// 2. 尝试终止线程池(如果是 SHUTDOWN 且队列为空,或 STOP)
tryTerminate();
// 3. 如果线程池还在运行,且线程数 < corePoolSize,补充线程
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; // 不需要补充
}
addWorker(null, false); // 补充一个线程(不带任务,从队列取)
}
}
五、核心线程 vs 非核心线程:本质区别
| 核心线程 | 非核心线程 | |
|---|---|---|
| 创建时机 | 任务提交时,线程数 < corePoolSize |
队列满时,线程数 < maximumPoolSize |
| 保活机制 | workQueue.take() 无限阻塞 |
workQueue.poll(keepAliveTime) 超时阻塞 |
| 回收条件 | 默认不回收(除非 allowCoreThreadTimeOut(true)) |
空闲超过 keepAliveTime 自动回收 |
| 本质 | 没有本质区别 ,都是 Worker 对象,只是回收策略不同 |
线程池内部没有"核心线程"和"非核心线程"的区分标记 ,纯粹是通过
wc > corePoolSize这个判断来决定使用take()还是poll()。
六、ctl:一个变量控制所有状态
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// ctl = 高3位(运行状态) + 低29位(线程数量)
private static final int COUNT_BITS = Integer.SIZE - 3; // 29
private static final int CAPACITY = (1 << COUNT_BITS) - 1; // 29位最大值
// 状态常量(高3位)
private static final int RUNNING = -1 << COUNT_BITS; // 111
private static final int SHUTDOWN = 0 << COUNT_BITS; // 000
private static final int STOP = 1 << COUNT_BITS; // 001
private static final int TIDYING = 2 << COUNT_BITS; // 010
private static final int TERMINATED = 3 << COUNT_BITS; // 011
| 状态 | 说明 |
|---|---|
RUNNING |
接收新任务,处理队列任务 |
SHUTDOWN |
不接收新任务,但处理队列中剩余任务(调用 shutdown()) |
STOP |
不接收新任务,不处理队列任务,中断正在执行的任务(调用 shutdownNow()) |
TIDYING |
所有任务完成,线程数为 0,准备执行 terminated() 钩子 |
TERMINATED |
terminated() 执行完毕 |
七、总结:线程生命周期全景图
┌─────────────────────────────────────────────────────────────┐
│ 线程池 ThreadPoolExecutor │
├─────────────────────────────────────────────────────────────┤
│ 任务提交 │
│ ↓ │
│ addWorker(firstTask, core) │
│ ↓ │
│ new Worker(firstTask) → ThreadFactory.newThread(this) │
│ ↓ │
│ thread.start() │
│ ↓ │
│ Worker.run() → runWorker(Worker) │
│ ↓ │
│ ┌─────────────────────────────────────┐ │
│ │ while (task != null || getTask() != null) │
│ │ ↓ │
│ │ w.lock() → task.run() → w.unlock() ← 循环复用 │
│ │ ↓ │
│ │ getTask() 返回 null → 退出循环 │
│ └─────────────────────────────────────┘ │
│ ↓ │
│ processWorkerExit(Worker, completedAbruptly) │
│ ↓ │
│ workers.remove(Worker) → 线程被 GC 回收 │
└─────────────────────────────────────────────────────────────┘
高频追问
Q:shutdown() 后线程池里的线程去哪了?
调用 shutdown() 后状态变为 SHUTDOWN,不再接收新任务。线程池会中断所有空闲线程 (通过 interruptIdleWorkers(),利用 Worker 的 AQS 锁判断空闲),让它们从 getTask() 的阻塞中醒来。醒来的线程发现状态是 SHUTDOWN 且队列为空,就会 return null 退出。
Q:shutdownNow() 为什么能立即停止任务?
状态变为 STOP,然后中断所有线程(无论空闲还是忙碌),清空队列。正在执行的任务如果响应中断会立即退出,不响应中断的则继续执行直到完成。
Q:如何设置核心线程也超时回收?
executor.allowCoreThreadTimeOut(true);
这样所有线程都用 poll(keepAliveTime) 取任务,超时后全部回收,线程池可以收缩到 0 个线程。