Phaser 的核心是按业务阶段动态注册/注销:初始用无参构造,工作线程就绪后调 register() 或 bulkRegister();注销依角色而异,一次性任务用 arriveAndDeregister(),长期线程用 arriveAndAwaitAdvance();阶段等待需用 awaitAdvance(phase) 避免竞态;onAdvance() 自定义流转逻辑,返回 true 可终止 Phaser。

Phaser 的多阶段注册和注销机制,核心是让线程按需加入、适时退出,而不是“一锅端”式地固定人数。它在复杂并发任务中真正落地的关键,不在于调用几个方法,而在于把注册/注销时机和业务阶段语义对齐。
注册必须发生在业务就绪之后,不能靠构造参数硬编码
很多团队一开始用 new Phaser(5),结果发现后续没法加新线程,或某批任务失败后无法收缩参与者。正确做法是:初始构造用无参方式,让主线程或协调者先注册,再由工作线程在真正准备好后自行注册。
- 预加载线程池启动时,每个 worker 在完成初始化(如连接数据库、加载配置)后调用
phaser.register() - 避免在 new Thread() 外提前注册——线程还没跑起来,注册了也白注册,还可能引发
IllegalStateException - 批量启动场景下,优先用
bulkRegister(n)替代循环register(),减少内部 CAS 竞争
注销要匹配角色生命周期,不是“做完就走”而是“不再参与后续阶段”
注销不是销毁线程,而是告诉 Phaser:“我这阶段干完了,下一阶段别等我”。比如数据清洗线程只负责第一阶段,汇总线程要贯穿全程,它们的注销策略完全不同。
- 一次性任务线程(如日志归档、临时校验)应在完成当前阶段后立即调用
arriveAndDeregister() - 长期值守线程(如监控上报、心跳维持)应始终使用
arriveAndAwaitAdvance(),不注销 - 主线程若仅用于分发任务,也要在分发完毕后调用
arriveAndDeregister(),否则会卡住 phase 推进
用 awaitAdvance(int phase) 实现精准阶段等待,避免竞态漏同步
直接调 arriveAndAwaitAdvance() 是常见写法,但在动态场景下容易出问题:比如子任务还没来得及 register,主线程就已推进到第二阶段。这时要用带 phase 参数的等待。
立即学习“Java免费学习笔记(深入)”;
- 主线程分发前记录当前 phase:
int p0 = phaser.getPhase(); - 所有子任务启动后,主线程调
phaser.awaitAdvance(p0),确保全部抵达第 0 阶段才继续 - 这个等待不依赖当前注册数,只看 phase 是否变化,适合注册有延迟的场景
onAdvance 自定义阶段流转逻辑,把同步变成可编程流程
默认的 phase 自增只是机械推进。复杂任务往往需要“第三阶段成功才进第四阶段”“某组失败则全局终止”。这些控制都放在 onAdvance() 里实现。
- 返回
true表示终止 Phaser,后续所有 arrive 调用立即返回,适合异常熔断 - 返回
false继续推进,可在其中做指标打点、资源清理、或根据registeredParties动态决定是否进入下一阶段 - 注意:onAdvance 内不能阻塞或耗时操作,否则拖慢整个屏障推进


















