Phaser是支持动态注册、按需退出、阶段精准等待的多阶段同步原语;其核心在于参与者可变与阶段隐式推进的组合,适用于任务数不确定、角色不一致的并发场景。

Phaser 不是“移相器”,也不是预设人数的阶段同步器,它本质是一个支持动态注册、按需退出、阶段精准等待的多阶段同步原语。它的进阶能力不在“多阶段”本身,而在于“参与者可变 + 阶段隐式推进”的组合——这使得它能自然适配任务数不确定、各阶段角色不一致的真实并发场景。
动态注册必须显式,不能靠构造参数“占位”
常见错误是写 new Phaser(5),以为这就有了 5 个合法参与者。实际上这只是让内部计数器起始为 5,不代表任何线程已注册。没调 register() 就直接 arrive(),必然抛出 IllegalStateException: Not a registered party。
- 正确起点是
new Phaser()或new Phaser(null, 0),从零开始 - 每个工作线程启动后、执行任务前第一件事:调
phaser.register() - 主线程若要参与同步(比如汇总结果),也得自己
register();若只协调不干活,就别注册,改用awaitAdvance(int)等待 - 批量注册可用
bulkRegister(int),比循环register()略快,但它仍是动作,不是声明上限
阶段性退出必须原子,不能拆成两步
线程完成某阶段后不再参与后续流程,必须用 arriveAndDeregister() 原子完成“到达 + 注销”。分写 arrive() 和 deregister() 是错的——deregister() 根本不是 public 方法。
- 预处理线程加载完数据 → 调
arriveAndDeregister(),立刻退出 - 汇总线程需等全部子任务结束 → 全程用
arriveAndAwaitAdvance()或配合awaitAdvance() - 主线程仅发号施令后退出 → 也要
arriveAndDeregister(),否则卡住 phase 推进 - 错误模式:
arriveAndAwaitAdvance()后再调arriveAndDeregister()—— 前者已阻塞并推进 phase,后者可能落在新 phase,导致计数错乱
阶段推进靠 awaitAdvance(int),不是盲目等待
主线程不干活,只观察节奏。它不该调 arriveAndAwaitAdvance(),而应调 awaitAdvance(int phase) 精准等待某阶段结束。
- 启动子任务前记下当前 phase:
int p0 = phaser.getPhase() - 分发完所有任务后调
phaser.awaitAdvance(p0),确保全部抵达第 0 阶段 - 再启动第 1 阶段逻辑(如校验),避免“部分还没开始,主线程已往下冲”
-
awaitAdvance()不自动arrive(),调用者自己必须先arrive()或arriveAndDeregister() - 返回后 phase 可能已跳变,别缓存 phase 值做后续判断
分组协同用嵌套 Phaser,避免单点瓶颈
当任务天然分组(如 4 组 worker 各自 map,再统一 reduce),平铺在一个 Phaser 下会导致语义混乱和竞争加剧。
- 创建父 Phaser:
Phaser root = new Phaser() - 每组启动时新建子 Phaser:
Phaser group = new Phaser(root)—— 构造时传入 parent,子 phaser 完成其 own phase 时会自动为 parentarrive() - 这样,父 phaser 的阶段推进代表“所有子组均已抵达当前阶段”,天然支持 Map-Reduce 类模式
- 调试时可用
phaser.getRegisteredParties()和phaser.getUnarrivedParties()实时观察状态

















