Phaser 实现灵活阶段同步的关键是“按需加入、精准抵达、适时退出、自动推进”:动态注册需显式调用 register();阶段推进靠已注册线程调用 arrive 系列方法触发;退出用 arriveAndDeregister();分组协同可构建父子 Phaser 树。

Phaser 实现灵活的阶段同步,关键在于“按需加入、精准抵达、适时退出、自动推进”这四个动作的配合,而不是靠预设人数或固定节奏硬等。
动态注册:谁干活,谁登记
参与者必须显式调用 register() 才算真正加入同步流程。构造时传参(如 new Phaser(5))只是初始化计数器,并不等于注册成功。未注册就调用 arriveAndAwaitAdvance() 会直接抛 IllegalStateException。
- 推荐起点:用
new Phaser()或new Phaser(null, 0)创建空 phaser - 每个工作线程启动后、执行任务前第一行就是
phaser.register() - 主线程若只发任务不干活,不必注册;若要参与汇总,也得自己
register() - 批量注册可用
bulkRegister(n),比循环调用稍高效,但仍属运行时动作
阶段推进:靠“到达”触发,不是定时轮询
Phaser 的 phase 编号从 0 开始,每次 +1,但这个递增不是自动发生的——只有已注册线程调用 arrive()、arriveAndAwaitAdvance() 或 arriveAndDeregister() 才会触发推进。没线程抵达,阶段就卡住不动。
-
arriveAndAwaitAdvance():最常用,表示“我到了,且要等别人”,返回时 phase 已+1 -
arrive():仅“发信号”,不阻塞,适合监控线程上报进度 -
awaitAdvance(int phase):主线程专用,需确保自己已抵达或由其他线程推动;调用前未抵达,会永远阻塞
阶段性退出:用 arriveAndDeregister() 一次完成
不是所有线程都要走完全部阶段。比如数据加载线程做完第 0 阶段就该释放,校验线程做完第 1 阶段就该退出,只有汇总线程全程参与。绕开同步(如用 if 判断跳过)会导致阶段卡死。
- 加载线程完成第 0 阶段后,立即调
phaser.arriveAndDeregister(),注册数实时减 1 - 校验线程在第 1 阶段末尾同样调
arriveAndDeregister() - 汇总线程全程用
arriveAndAwaitAdvance()等待全体抵达 - 切忌拆成
arrive()+ “手动注销”——后者根本不存在;也别在arriveAndAwaitAdvance()后再调arriveAndDeregister(),易导致计数错乱
分组协同:父子 Phaser 构建树状结构
当任务天然分组(如 4 组 worker 各自 map,再统一 reduce),单个 Phaser 容易语义混乱。此时应采用嵌套结构:
- 父 phaser 控制全局节奏,每个子组创建自己的
new Phaser(parent) - 子组内所有成员抵达当前 phase 后,子 phaser 自动为父 phaser 调用
arrive() - 这样,父 phaser 的 phase 推进就代表“所有子组已同步完成当前轮”,天然适配 Map-Reduce 类模式
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











