phaser 可替代 countdownlatch 实现多阶段循环同步,因其支持重复使用、动态注册/注销参与者及自动推进阶段;countdownlatch 一旦计数归零不可重置,无法适应循环或多变参与数场景。

Phaser 可以替代 CountDownLatch 实现多阶段循环同步,关键在于它支持**重复使用**和**动态注册/注销参与者**,而 CountDownLatch 一旦计数归零就不可重置,无法应对循环或多阶段场景。
用 Phaser 模拟 CountDownLatch 的基础结构
CountDownLatch 常用于“等待所有线程完成某阶段”,比如启动前等待全部就绪。Phaser 通过 register() 和 arriveAndAwaitAdvance() 实现类似语义:
- 主线程调用 phaser.register() 作为“协调者”(相当于 latch 的 count)
- 每个工作线程调用 phaser.register() 注册自己,再执行任务,最后调用 phaser.arriveAndAwaitAdvance()
- 主线程在所有线程注册后也调用 arriveAndAwaitAdvance() —— 此时会阻塞,直到所有已注册线程都到达同一阶段
这样就等效于 CountDownLatch.await():所有线程到达后才继续下一阶段。
支持多阶段循环的关键:arriveAndAwaitAdvance() 自动推进阶段
Phaser 的每个 arriveAndAwaitAdvance() 调用不仅等待,还会把当前 phase 加 1。下一轮循环中,所有线程再次调用该方法,自然进入 phase+1,无需重置或重建对象。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- CountDownLatch 每轮都需要 new 一个新实例,而 Phaser 复用同一个实例即可
- phase 编号从 0 开始递增,可通过 getPhase() 查看当前阶段,便于日志或条件判断
- 如果某轮有线程临时退出,可用 arriveAndDeregister() 减少参与数,其他线程仍能正常同步
动态调整参与者数量(CountDownLatch 做不到)
实际业务中,每轮参与的线程数可能变化(如部分 worker 因负载关闭)。Phaser 允许运行时增减:
- 新增线程调用 phaser.register(),自动加入下一阶段同步
- 退出线程调用 phaser.arriveAndDeregister(),后续阶段不再等待它
- 可通过 getRegisteredParties() 和 getArrivedParties() 监控状态,避免因漏注册导致死锁
例如:一个批处理系统每轮读取不同数量的分片,每个分片由独立线程处理 —— Phaser 可按需注册,CountDownLatch 必须预先知道总数且固定不变。
注意终止与异常处理
Phaser 不会因异常自动终止,需主动管理:
- 任意线程调用 forceTermination() 后,后续 arriveAndAwaitAdvance() 立即返回负值(表示已终止),避免卡死
- 建议在 catch 块中调用 forceTermination(),并检查返回值是否为负,及时退出循环
- CountDownLatch 没有内置终止机制,异常后往往只能靠超时或外部中断挽救
不复杂但容易忽略:多阶段循环中,别忘了在每轮开始前确认 phaser 未被终止,尤其在 retry 场景下。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










