为保证线程池运行状态与工作线程数更新的原子性,ThreadPoolExecutor用单个AtomicInteger(ctl)高位存3位状态、低位存29位数量,通过位运算实现无锁、一致、高效的状态-数量协同变更。

Java 中的线程池(如 ThreadPoolExecutor)使用一个名为 ctl 的 AtomicInteger 原子变量,**同时编码线程池运行状态和工作线程数量**,其中高 3 位表示运行状态(RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED),低 29 位表示当前活跃线程数(即 worker 数量)。
为什么用一个 int 同时存两个信息?
这是空间与原子性的权衡:用单个 AtomicInteger 可以保证「状态 + 数量」的更新是原子的,避免加锁或 CAS 失败重试的复杂性。32 位中,3 位状态(最多 8 种,实际只用 5 种)+ 29 位数量(最大支持约 5.3 亿线程,远超实际需求),设计紧凑且足够安全。
ctl 的位布局与常量定义
ThreadPoolExecutor 内部定义了关键掩码:
-
运行状态掩码(高 3 位):
COUNT_BITS = 29,CAPACITY = (1 << COUNT_BITS) - 1 = 0x1FFFFFFF(低 29 位全 1) -
状态取值(左移 29 位):
-
RUNNING = -1 << COUNT_BITS = 0xFFFFFFFE00000000(高 3 位为 111) -
SHUTDOWN = 0 << COUNT_BITS = 0x00000000(高 3 位为 000) -
STOP = 1 << COUNT_BITS = 0x20000000(高 3 位为 001) -
TIDYING = 2 << COUNT_BITS = 0x40000000(高 3 位为 010) -
TERMINATED = 3 << COUNT_BITS = 0x60000000(高 3 位为 011)
-
如何读取和修改 ctl?
所有操作都基于位运算,不直接暴露原始值:
立即学习“Java免费学习笔记(深入)”;
-
获取运行状态:`ctl.get() & ~CAPACITY` —— 按位取反
CAPACITY得到状态掩码(0xE0000000),再与ctl按位与,即可提取高 3 位 - 获取线程数量:`ctl.get() & CAPACITY` —— 直接与低 29 位掩码按位与,清零高 3 位
- 设置新状态 + 数量:`ctl.compareAndSet(expect, (runState & ~CAPACITY) | (workerCount & CAPACITY))` —— 先清高 3 位,再填入新状态;清低 29 位,再填入新数量;最后 CAS 更新
典型使用场景举例
比如执行 shutdown() 方法时:
- 先 `ctl.get()` 读当前值
- 检查状态是否为
RUNNING(否则不处理) - 构造新 ctl 值:`(SHUTDOWN & ~CAPACITY) | (currentWorkerCount & CAPACITY)`
- 调用 `ctl.compareAndSet(old, new)` 尝试更新——成功则状态切换完成,失败则重试
这种设计让状态迁移和数量变更始终保持一致,不会出现「状态已 SHUTDOWN,但线程数还在增长」这类竞态问题。


















