Phaser是Java并发包中支持动态注册/注销参与者和隐式阶段推进的同步工具,适用于任务数不确定、阶段行为不一致的场景;必须显式调用register(),避免IllegalStateException;arrive()留待下一阶段,arriveAndDeregister()退出;awaitAdvance()需先arrive()再等待指定phase;嵌套Phaser可实现分组与全局两级同步;onAdvance()中禁止阻塞操作。
不是“移相器”,这是常见误译。它本质是 Java 并发包中支持
动态注册/注销参与者 + 隐式阶段推进
的同步工具,专为任务数不确定、阶段行为不一致的场景设计。
初始化时别传固定人数,也别用空构造就开跑
直接
会把第一阶段锁死在 5 个参与者,后续无法增减;而
虽然灵活,但若没人调
,线程一调
就立刻返回——因为当前阶段压根没人“守门”,根本不会等待。
必须在任务线程真正进入同步逻辑前,显式调用
若初始无参与者,就用
或
切忌依赖“自动注册”——
是必须手动触发的动作
常见错误现象:
,基本就是某个线程没
就直接
了。
每个阶段用 arrive() 还是 arriveAndDeregister()?看它参不参与下一阶段
表示“我这阶段干完了”,但还留在池子里等下一阶段;
表示“我干完就走,不陪你们进下一轮”。
预处理线程只负责加载数据 → 完成后应调
汇总线程要等所有子任务结束再启动 → 应全程用
主线程若只负责协调(比如分发任务后就退出),也要记得
,否则会卡住整个 phaser 的 phase 推进
性能影响:频繁
会引发内部数组重分配,如果任务粒度极小(如纳秒级计算),建议批量合并或换用
链式编排。
用 awaitAdvance() 精确等待某阶段结束,而不是盲目阻塞
是最可控的等待方式:它只等指定 phase 结束,不关心当前有多少人注册。
启动子任务前记录当前 phase:
分发完所有任务后调
,确保全部子任务都抵达第 0 阶段
再启动第 1 阶段逻辑(如校验),避免“部分子任务还没开始,主线程就往下冲”
注意:
不会自动
,调用者自己得先
或
,否则永远等不到。
嵌套 Phaser 处理分组+全局两级同步
当任务天然分组(如 3 组 worker,每组内同步,组间再统一汇总),用父子
最自然:
创建父
每组新建子
(构造时传 parent)
子组内线程正常
和
子
完成本阶段时,会自动为父
这样,
就代表“所有组都完成了第 1 阶段”,不用手动计数或轮询。
容易踩的坑:
回调里不能做任何可能阻塞的操作(比如再等另一个
),否则会死锁——这个方法运行在
内部锁下。
复杂点在于:phase 推进是隐式的,状态变化不直观。调试时多用
和
实时查数,比加日志靠谱得多。
Phasernew Phaser(5)new Phaser()register()arriveAndAwaitAdvance()phaser.register()new Phaser()new Phaser(null, 0)register()IllegalStateException: Not a registered partyregister()arrive()arrive()arriveAndDeregister()arriveAndDeregister()arriveAndAwaitAdvance()arriveAndDeregister()arriveAndDeregister()CompletableFuture.join()phaser.awaitAdvance(int phase)int p0 = phaser.getPhase();phaser.awaitAdvance(p0)awaitAdvance()arrive()arrive()arriveAndDeregister()PhaserPhaser root = new Phaser();Phaser group = new Phaser(root);register()arriveAndAwaitAdvance()Phaserphaser.arrive()root.awaitAdvance(1)onAdvance()PhaserPhaserphaser.getRegisteredParties()phaser.getUnarrivedParties()