phaser是专用于单jvm内多线程分阶段协作的轻量协调器,核心价值在于动态参与者数量、多阶段推进和生命周期精准对齐;其phase从0单调递增,仅当所有已注册参与者到达后才自动+1,需显式register()和arriveandderegister(),且必须“一次一例”绑定任务生命周期。

Phaser不是为跨服务或分布式场景设计的,而是专用于单JVM内多线程分阶段协作的轻量协调器。它真正发挥价值的地方,是把“动态参与者数量 + 多阶段推进 + 生命周期精准对齐”这三件事在本地任务调度中做到可控、可观测、可终止。
阶段推进必须由到达行为自然驱动
Phaser内部维护一个从0开始单调递增的phase编号,不靠定时器、不靠外部触发——只有当所有已注册参与者都完成当前阶段,phase才自动+1。这个机制决定了同步逻辑必须围绕“谁到了、谁没到、谁退出了”来组织。
- 调用arriveAndAwaitAdvance()的线程会阻塞,直到本阶段全员就位,然后进入下一阶段;适合需要严格同步的主线程或汇总线程
- 调用arrive()只上报完成状态,不等待,适合异步日志、监控埋点等旁路操作
- 主线程可通过getPhase()实时读取当前阶段号,用于判断是否该启动校验、降级或告警
参与者管理必须运行时显式控制
不能靠构造参数“占位”,比如new Phaser(5)只是设初始计数器为5,并不代表已有5个合法参与者。没调register()就直接调用同步方法,必定抛IllegalStateException: Not a registered party。
- 每个工作线程启动后、执行业务逻辑前,第一件事就是调phaser.register()
- 线程完成某阶段后不再参与后续流程,必须用arriveAndDeregister()原子完成“到达+注销”,分开写arrive()和deregister()是错的(后者根本不是public方法)
- 主线程若仅做调度不干活,可不注册;若要参与汇总或兜底,则同样需register(),并在最后arriveAndDeregister()
任务生命周期必须与Phaser实例严格绑定
Phaser不应作为静态全局对象复用,而应“一次一例”:每次任务调度(如按taskID+triggerTime)创建新实例。这种设计避免状态污染、阶段错乱和内存泄漏。
- 调度器触发时,新建new Phaser(1),让主线程先占位
- 各分片线程启动后注册成功,才开始执行逻辑,确保计数准确
- 任一子任务抛未捕获异常,主线程可调forceTermination()强制终止,其余等待线程立即收到IllegalStateException并退出
- 所有线程注销完毕后,Phaser自动进入终止态,无需手动清理
复杂场景推荐分层或嵌套结构
当任务天然分组(例如4组worker各自map,再统一reduce),平铺在一个Phaser下会导致语义模糊和锁竞争加剧。应采用父子Phaser结构:
- 每组内部使用独立子Phaser,负责组内线程阶段对齐
- 主Phaser协调各子组整体进度,例如等全部子组完成map后,才推进到reduce阶段
- 子Phaser注册到父Phaser时,其参与者变化会自动同步到父级,减少手动计数负担











