线程池从running到shutdown的转换仅由显式调用shutdown()触发,此时拒绝新任务但继续执行队列中及运行中的任务,状态通过ctl原子变量cas更新,不可逆且线程安全。

线程池从 RUNNING 到 SHUTDOWN 的转换,本质是主动发起“优雅关闭”的信号,不是自动发生,而是由开发者显式调用 shutdown() 方法触发的。
RUNNING → SHUTDOWN 的触发条件
这个状态跃迁只有一种标准方式:
- 调用
executor.shutdown()—— 这是唯一合法且受控的入口 - 极少数情况下,线程池对象被 GC 回收时,
finalize()可能隐式调用 shutdown(),但该机制已被标记为 deprecated,不应依赖
状态切换时的实际行为变化
一旦进入 SHUTDOWN 状态,线程池立刻改变对任务和线程的处理逻辑:
- 新提交的任务(如
execute()或submit())会直接抛出RejectedExecutionException - 阻塞队列中已排队但尚未执行的任务,仍会被工作线程陆续取出并执行
- 正在运行中的任务不受影响,继续执行直到完成
- 线程不会立即销毁,而是等当前任务结束、队列变空后自然退出
底层怎么保证这个切换是原子且安全的
ThreadPoolExecutor 用一个 AtomicInteger ctl 同时存状态和线程数,高 3 位是状态码。RUNNING 是 0xE0000000(二进制 111 开头),SHUTDOWN 是 0x00000000(000 开头)。切换时通过 CAS 原子更新整个 ctl 值,确保:
- 多个线程并发调用 shutdown(),只有第一个成功;其余调用立即返回,不重复变更状态
- 状态检查(比如判断是否已关闭)只需
ctl & ~CAPACITY提取高 3 位,无锁高效 - 状态不可逆,一旦设为 SHUTDOWN,就再也回不到 RUNNING
怎么确认已经进入 SHUTDOWN 状态
不能靠 sleep 等待,而应结合状态查询与等待逻辑:
- 用
isShutdown()判断是否已调用 shutdown() - 用
isTerminated()判断是否所有任务都已完成(即已到 TERMINATED) - 更常用的是
awaitTermination(long timeout, TimeUnit unit)阻塞等待任务清空,超时则可决定是否 fallback 到 shutdownNow()
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











