前言
本文深度剖析JDK 17线程池(ThreadPoolExecutor)源码实现,揭示其高效处理百万级并发任务的核心设计。通过解析ctl原子状态控制、Worker执行单元双角色机制、三级缓冲任务调度流程(核心线程→队列→非核心线程)及优雅关闭状态机,展现Java并发大师Doug Lea的工程智慧。结合时序图与设计模式分析,深入探讨线程复用、动态扩缩容和资源管控等关键技术,并指出ThreadLocal污染等典型陷阱的解决方案,为构建高并发系统提供底层原理支撑。
一、核心设计思想
JDK线程池(java.util.concurrent.ThreadPoolExecutor)基于生产者-消费者模型实现,核心设计原则:
- 线程复用:避免频繁创建/销毁线程的开销
- 资源管控:通过核心/最大线程数控制并发资源
- 任务排队:阻塞队列缓冲任务请求
- 拒绝策略:过载保护机制
值得借鉴的设计及意图推断:
- 状态压缩设计:将状态和线程数合并为单个原子整型(
ctl),避免多字段更新的竞态条件 - Worker封装:将线程和任务绑定,实现任务执行单元和锁控制的统一
- 钩子方法:提供
beforeExecute/afterExecute扩展点,支持监控等横切关注点
二、核心数据结构
1. 状态控制字段 ctl
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
- 32位整型:高3位存储线程池状态,低29位存储工作线程数
- 状态定义:
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
设计模式:状态模式(State Pattern)通过状态流转实现生命周期管理
2. 工作线程容器
private final HashSet<Worker> workers = new HashSet<>();
- Worker:核心工作单元,封装线程和任务
- 线程安全:所有访问通过ReentrantLock同步
private final ReentrantLock mainLock = new ReentrantLock();
三、任务执行流程分析
1. execute(Runnable command)源码分析
public void execute(Runnable command) {
// 步骤1:空任务检查
if (command == null)
throw new NullPointerException();
// 获取当前控制状态(包含线程池状态+工作线程数)
int c = ctl.get();
// 步骤2:尝试创建核心线程
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true)) // true表示创建核心线程
return; // 创建成功直接返回
c = ctl.get(); // 创建失败重新获取状态
}
// 步骤3:尝试任务入队
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); // 创建无初始任务的非核心线程
}
// 步骤4:尝试创建非核心线程
else if (!addWorker(command, false)) // false表示非核心线程
// 步骤5:执行拒绝策略
reject(command);
}
2. 执行步骤
-
核心线程处理:当新任务提交时,线程池优先检查当前工作线程数是否小于
corePoolSize。若是,则立即创建新工作线程处理该任务。 -
任务入队:如果核心线程已满,线程池尝试将任务放入阻塞队列(如
LinkedBlockingQueue)。入队成功后,会重新获取线程池状态控制变量,进行线程池状态和线程数量检查:2.1 线程池已经关闭(可能其他地方执行了
shutdown()或shutdownNow()),则移除任务并执行拒绝策略(防止关闭后继续接收任务)。2.2 如果线程池为
RUNNING状态,则检查线程池中线程数量是否为0,如果为0,则创建无初始任务的非核心线程(allowCoreThreadTimeOut控制是否允许核心线程超时回收,防止所有线程终止导致任务积压)。 -
非核心线程处理:当队列已满且工作线程数小于
maximumPoolSize时,创建非核心线程处理任务。 -
拒绝策略:当队列满且线程数达到
maximumPoolSize后,新提交的任务将触发拒绝策略(如抛出RejectedExecutionException)。
3. 执行时序图:
sequenceDiagram
participant Caller as 调用线程
participant TPE as ThreadPoolExecutor
participant Queue as 阻塞队列
participant Worker as 工作线程
Caller->>TPE: execute(task)
alt 核心线程未满
TPE->>Worker: addWorker(task, true)
Worker-->>TPE: true
TPE-->>Caller: return
else 队列未满
TPE->>Queue: offer(task)
alt 无工作线程
TPE->>Worker: addWorker(null, false)
end
else 可创建非核心线程
TPE->>Worker: addWorker(task, false)
else 拒绝策略
TPE->>TPE: reject(task)
end
四、创建线程源码分析
1. 方法签名
private boolean addWorker(Runnable firstTask, boolean core)
- firstTask:线程执行的第一个任务(可为null)
- core:true表示核心线程,false表示非核心线程
- 返回值:线程创建是否成功
2. 状态检查与循环重试
retry:
for (int c = ctl.get();;) {
// 状态合法性验证
if (runStateAtLeast(c, SHUTDOWN) &&
(runStateAtLeast(c, STOP) || // 条件1:STOP状态禁止创建
firstTask != null || // 条件2:SHUTDOWN状态禁止新任务
workQueue.isEmpty())) // 条件3:队列空时禁止创建无任务线程
return false;
for (;;) {
// 容量限制检查
int wc = workerCountOf(c);
if (workerCountOf(c)
>= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK)) // 核心/非核心限制
return false;
// 无锁化线程计数更新
if (compareAndIncrementWorkerCount(c)) // CAS更新线程计数
break retry; // 成功则跳出
// 状态变化感知
c = ctl.get();
if (runStateAtLeast(c, SHUTDOWN))
continue retry; // 状态变化时重试外层检查
}
}
关键设计:
- 双重循环:外层处理状态变更,内层处理线程计数
- CAS原子操作:确保线程计数增加的安全性
- 状态优先原则:先检查线程池状态,再处理线程创建
2. Worker对象创建与启动
Worker w = null;
boolean workerStarted = false;
boolean workerAdded = false;
try {
// Worker实例化
w = new Worker(firstTask); // 封装任务和线程
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock(); // 获取全局锁
try {
// 二次状态校验
int c = ctl.get();
if (isRunning(c) ||
(runStateLessThan(c, STOP) && firstTask == null)) {
// 线程状态验证
if (t.getState() != Thread.State.NEW)
throw new IllegalThreadStateException();
// 安全加入集合
workers.add(w);
workerAdded = true;
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
}
} finally {
mainLock.unlock();
}
// 锁外启动线程
if (workerAdded) {
t.start(); // 不在锁内启动!
workerStarted = true;
}
}
} finally {
// 异常回滚机制
if (!workerStarted)
addWorkerFailed(w);
}
关键设计:
- 锁保护:
mainLock保护workers集合操作 - 二次状态检查:防止启动前状态变化
- 异常回滚:
addWorkerFailed处理创建失败
五、Worker核心实现
1. Worker类结构
private final class Worker extends AbstractQueuedSynchronizer implements Runnable {
final Thread thread; // 实际执行线程
Runnable firstTask; // 初始任务
Worker(Runnable firstTask) {
setState(-1); // 禁止中断直到runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
public void run() {
runWorker(this); // 委托给线程池方法
}
// 实现简单的不可重入锁
// The value 0 represents the unlocked state.
// The value 1 represents the locked state.
protected boolean isHeldExclusively() {
return getState() != 0;
}
protected boolean tryAcquire(int unused) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
protected boolean tryRelease(int unused) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
}
2. 任务执行循环 runWorker()
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // 允许中断
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
w.lock(); // 获取Worker锁
// 中断处理逻辑...
try {
beforeExecute(wt, task); // 钩子方法
try {
task.run(); // 执行任务
afterExecute(task, null); // 钩子方法
} catch (Throwable ex) {
afterExecute(task, ex); // 异常处理
throw ex;
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly); // 清理工作线程
}
}
设计模式:模板方法模式(Template Method)通过beforeExecute/afterExecute提供扩展点
六、任务获取机制 getTask()
private Runnable getTask() {
boolean timedOut = false; // 上次poll是否超时
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// 检查状态:SHUTDOWN+空队列 或 STOP状态
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// 是否允许超时(核心线程可超时 或 线程数>corePoolSize)
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : // 超时获取
workQueue.take(); // 阻塞获取
if (r != null)
return r;
timedOut = true; // 获取超时
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
设计意图:通过超时机制实现空闲线程回收,动态调整线程池大小
七、线程回收机制
1. 超时回收
- 当
getTask()返回null时触发线程退出 - keepAliveTime:非核心线程空闲存活时间
- allowCoreThreadTimeOut:核心线程是否允许超时
2. 异常回收
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // 异常退出
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
workers.remove(w); // 从集合移除
} finally {
mainLock.unlock();
}
tryTerminate(); // 尝试终止线程池
// 维持最小线程数
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); // 补充新Worker
}
}
设计意图:确保线程池具备自愈能力,在异常退出时自动补充新线程
八、关闭流程分析
1. shutdown() 平滑关闭
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
advanceRunState(SHUTDOWN); // 更新状态
interruptIdleWorkers(); // 中断空闲线程
onShutdown(); // 钩子方法
} finally {
mainLock.unlock();
}
tryTerminate();
}
2. shutdownNow() 立即关闭
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
advanceRunState(STOP); // 强制STOP状态
interruptWorkers(); // 中断所有工作线程
tasks = drainQueue(); // 排出队列任务
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}
设计意图:提供两种关闭模式,满足不同场景的关闭需求
九、拒绝策略实现
内置四种拒绝策略均实现RejectedExecutionHandler:
// 1. 默认策略:抛出异常
public static class AbortPolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException();
}
}
// 2. 调用者运行策略
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run(); // 在调用线程执行
}
}
}
// 3. 丢弃策略
public static class DiscardPolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {}
}
// 4. 丢弃最老策略
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll(); // 丢弃队列头任务
e.execute(r); // 重试执行
}
}
}
设计模式:策略模式(Strategy Pattern)允许灵活替换拒绝策略
十、关键设计亮点
-
状态压缩设计:
- 32位ctl字段同时编码状态和线程数
- 避免多字段更新的原子性问题
-
Worker双角色设计:
- 既是任务执行单元(Runnable)
- 又是同步控制单元(继承AQS)
-
优雅关闭机制:
- SHUTDOWN模式:继续处理队列任务
- STOP模式:立即中断所有线程
-
动态线程调整:
- 根据负载自动扩缩容
- 核心线程可配置超时
-
异常处理机制:
- 任务异常通过afterExecute暴露
- 工作线程异常自动补充新线程
十一、线程池使用陷阱和扩展
1. ThreadLocal污染问题
问题现象:
// 用户身份上下文
static ThreadLocal<User> currentUser = new ThreadLocal<>();
executor.execute(() -> {
currentUser.set(loadUser()); // 任务1设置用户A
doSomeWork();
// 未清理ThreadLocal
});
executor.execute(() -> {
// 可能读取到用户A的数据!
User user = currentUser.get();
});
解决方案:
executor.execute(() -> {
try {
currentUser.set(loadUser());
doSomeWork();
} finally {
currentUser.remove(); // 强制清理
}
});
2. 死锁陷阱
// 同一线程池提交相互依赖任务
executor.submit(taskA); // taskA等待taskB结果
executor.submit(taskB); // taskB等待taskA结果
解决方案:使用不同线程池或ForkJoinPool
3. 资源泄漏陷阱
ExecutorService pool = Executors.newCachedThreadPool();
pool.execute(() -> { ... });
// 忘记shutdown()导致线程无法回收
解决方案:
try (ExecutorService pool = Executors.newVirtualThreadPerTaskExecutor()) {
pool.execute(task);
} // 自动关闭(JDK21+)
4. 异常吞噬陷阱
executor.execute(() -> {
throw new RuntimeException("被吞没!");
});
// 主线程无法捕获异常
解决方案:
// 方案1:重写afterExecute
protected void afterExecute(Runnable r, Throwable t) {
if (t != null) logger.error("Uncaught exception", t);
}
// 方案2:使用Future
Future<?> future = executor.submit(task);
try {
future.get();
} catch (ExecutionException e) {
handle(e.getCause());
}
5. 监控扩展:
public class MonitorThreadPool extends ThreadPoolExecutor {
// 任务开始/结束监控
protected void beforeExecute(Thread t, Runnable r) {
monitor.recordStart(r, t);
}
protected void afterExecute(Runnable r, Throwable t) {
monitor.recordEnd(r, t);
}
// 线程创建/销毁监控
protected void terminated() {
monitor.poolShutdown();
}
}
总结
Java线程池的执行流程本质上是生产者-消费者模型的优化实现,其核心设计思想是通过三级缓冲实现资源弹性分配。