ThreadPoolExecutor 的运行状态和线程数由 ctl 原子整型字段统一编码控制——高3位表示 RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED 五种状态,低29位记录活跃线程数;所有状态转换均通过 CAS 修改 ctl 实现线程安全。

ThreadPoolExecutor 的运行状态不是抽象概念,而是由一个叫 ctl 的原子整型字段直接编码控制的——高 3 位存状态,低 29 位存当前活跃线程数。搞懂这个设计,就能从代码层面看清线程池“怎么活、怎么停、怎么死”。
ctl 字段:一个整数承载两种关键信息
ctl 是线程池真正的“生命仪表盘”。它用一个 int(32 位)同时记录:
- 运行状态(高 3 位):共 5 种取值,对应 RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED
- 工作线程数量(低 29 位):最大支持 2²⁹ − 1 ≈ 5.36 亿个线程(实际远达不到)
比如:ctl = -536870912(二进制高 3 位为 111)表示 RUNNING 状态;ctl = -1073741824(高 3 位为 100)表示 SHUTDOWN。所有状态转换都通过 CAS 操作 ctl 完成,保证线程安全。
RUNNING → SHUTDOWN:温柔收尾,不拒旧账
调用 shutdown() 会尝试把 ctl 从 RUNNING 状态(值为 -536870912)更新为 SHUTDOWN(-1073741824)。成功后:
- 不再接受新提交的任务(
execute()会直接抛RejectedExecutionException) - 但继续处理阻塞队列中已有的任务,也允许正在运行的线程跑完
- 此时若队列为空、所有 worker 已退出,ctl 中线程数变为 0,状态自动升级为 TIDYING
RUNNING → STOP:硬中断,清场式关停
调用 shutdownNow() 会尝试把 ctl 更新为 STOP(-1610612736)。触发后:
- 拒绝所有新任务(包括刚进队列还没来得及执行的)
- 对所有正在运行的 Worker 调用
Thread.interrupt() - 尝试清空工作队列(
workQueue.drainTo()),返回未执行任务列表 - 一旦所有 worker 彻底终止、线程数归零,状态立即进入 TIDYING
TIDYING → TERMINATED:善后钩子与终局确认
TIDYING 是一个瞬时中间态:所有任务终止、workerCount == 0、状态正待收尾。此时线程池会自动调用 terminated() 钩子方法(可被子类重写用于清理资源、发通知等)。该方法执行完毕后,ctl 状态才正式设为 TERMINATED。
注意:只有到达 TERMINATED,awaitTermination() 才会返回 true;也只有这时,线程池才真正“寿终正寝”,不能再被复用。










