外观
线程池有几种状态?
⭐ 题目日期:
快手 - 2024/12/29
📝 题解:
线程池的状态通常用于管理其生命周期,确保任务能够被合理调度和资源得到有效回收。以Java中的ThreadPoolExecutor
为例,线程池共有以下五种状态:
1. RUNNING(运行中)
- 状态值:
RUNNING
(数值表示的高3位为111
) - 特点:
- 接受新任务:可以继续提交新的任务。
- 处理队列任务:执行已提交到任务队列中的任务。
- 正常工作模式:线程池初始化后的默认状态。
- 状态转换:
- 调用
shutdown()
→ 进入 SHUTDOWN。 - 调用
shutdownNow()
→ 进入 STOP。
- 调用
2. SHUTDOWN(关闭中)
- 状态值:
SHUTDOWN
(高3位为000
) - 特点:
- 不再接受新任务:新提交的任务会被拒绝(触发
RejectedExecutionException
)。 - 处理现有任务:继续执行任务队列中已存在的任务。
- 优雅关闭:适用于希望平稳结束任务的场景。
- 不再接受新任务:新提交的任务会被拒绝(触发
- 状态转换:
- 任务队列为空且工作线程数为0 → 进入 TIDYING。
- 调用
shutdownNow()
→ 进入 STOP。
3. STOP(停止)
- 状态值:
STOP
(高3位为001
) - 特点:
- 立即中断任务:尝试停止所有正在执行的任务(通过
Thread.interrupt()
)。 - 丢弃队列任务:不再处理任务队列中的任务,并返回未执行的任务列表。
- 强制关闭:适用于需要立即释放资源的场景。
- 立即中断任务:尝试停止所有正在执行的任务(通过
- 状态转换:
- 所有工作线程终止 → 进入 TIDYING。
4. TIDYING(整理中)
- 状态值:
TIDYING
(高3位为010
) - 特点:
- 过渡状态:所有任务已终止,工作线程数为0。
- 执行钩子方法:调用
terminated()
方法(用户可覆盖此方法进行自定义清理)。
- 状态转换:
terminated()
执行完毕 → 进入 TERMINATED。
5. TERMINATED(已终止)
- 状态值:
TERMINATED
(高3位为011
) - 特点:
- 最终状态:线程池完全关闭,不再响应任何操作。
- 资源释放:所有资源(如线程、队列)已回收。
状态转换示意图
RUNNING → shutdown() → SHUTDOWN → 队列空且线程数为0 → TIDYING → terminated() → TERMINATED
│
└→ shutdownNow() → STOP → 线程数为0 → TIDYING → terminated() → TERMINATED
关键设计点
状态位编码: Java使用
AtomicInteger
的高3位表示状态,低29位表示工作线程数,通过位运算高效管理状态和线程数。private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); private static final int COUNT_BITS = 29; private static final int CAPACITY = (1 << COUNT_BITS) - 1; // 状态常量 private static final int RUNNING = -1 << COUNT_BITS; private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS;
拒绝策略: 在 SHUTDOWN 或 STOP 状态下提交任务会触发拒绝策略(如抛出异常、丢弃任务等)。
实际应用场景
- RUNNING:正常处理高并发请求。
- SHUTDOWN:服务重启前等待存量任务完成。
- STOP:紧急终止服务,避免资源泄漏。
- TERMINATED:线程池彻底销毁,释放JVM资源。
总结
线程池的五种状态(RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED)共同管理其生命周期,确保任务调度和资源回收的安全性。理解这些状态及其转换逻辑,有助于合理使用线程池并避免常见问题(如任务丢失、资源泄漏)。