Phaser 是 Java 并发包中支持动态增减线程与多阶段协同的同步工具,核心特性为运行时注册/注销参与者、自动阶段推进及树形结构扩展能力。

Phaser 是 Java 并发包中一个功能强大且灵活的同步辅助类,特别适合处理线程数量动态变化的多阶段协同场景。它比 CountDownLatch 更灵活、比 CyclicBarrier 更可扩展,核心在于支持运行时注册/注销参与者,并能分阶段推进。
理解 Phaser 的生命周期与角色
Phaser 的关键在于“阶段(phase)”和“参与者(party)”两个概念:每个 arrive() 或 arriveAndAwaitAdvance() 都会推进当前阶段;当所有已注册的参与者都到达后,阶段自动加 1,进入下一阶段。参与者可通过 register() 动态加入,也可通过 arriveAndDeregister() 主动退出,整个过程线程安全。
- 初始构造时可指定预估参与数(如
new Phaser(3)),也可无参构造后动态注册 - Phaser 支持树形结构(parent-child),适用于大规模或分组协调,但多数场景用单个实例即可
- 调用 getPhase() 可读取当前阶段号(从 0 开始),用于判断执行上下文
动态增减线程的典型用法
假设一批任务由多个工作线程并行执行,但某些线程中途完成并退出,新线程又可能随时加入——这时用 Phaser 比固定数量的栅栏更自然。
- 主线程创建 Phaser 后,每个工作线程启动前调用
phaser.register()注册自己 - 线程在每阶段末调用
phaser.arriveAndAwaitAdvance()等待全体就绪再继续 - 线程完成全部工作后,调用
phaser.arriveAndDeregister()退出,不影响其他线程后续阶段 - 新增线程可随时调用
register()加入,Phaser 自动将其纳入下一阶段的计数
避免常见陷阱的实践建议
Phaser 强大但易误用,尤其在动态场景下需注意状态一致性。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
立即学习“Java免费学习笔记(深入)”;
- 不要在 deregister 后再调用 arrive 类方法:已注销线程若误触发同步操作,会抛出 IllegalStateException
-
阶段推进是隐式的:即使只有一个线程调用
arriveAndAwaitAdvance(),只要它是当前阶段最后一个到达者,阶段就会前进——注意这可能导致“空推进” - 监听阶段变更可用 onAdvance() 回调:重写该方法可做阶段初始化、清理或条件判断(返回 true 表示终止,后续 arrive 不再推进阶段)
- 调试时善用
getRegisteredParties()和getArrivedParties()查看实时状态,比日志更可靠
一个简明的动态协作示例
模拟数据分片处理:初始 2 个线程处理前两批数据;中途第 3 个线程加入处理新批次;第 1 个线程完成后主动退出。
Phaser phaser = new Phaser();
// 启动前两个线程,各自 register
new Thread(() -> {
phaser.register();
process("A");
phaser.arriveAndAwaitAdvance(); // 第一阶段结束
process("A2");
phaser.arriveAndDeregister(); // 主动退出
}).start();
new Thread(() -> {
phaser.register();
process("B");
phaser.arriveAndAwaitAdvance();
process("B2");
}).start();
// 稍后启动第三个线程
new Thread(() -> {
phaser.register(); // 动态加入
process("C");
phaser.arriveAndAwaitAdvance();
process("C2");
}).start();
三者会在第一阶段同步等待(A/B 到达即推进),第二阶段因 A 已注销,仅 B/C 参与同步——逻辑清晰,无需重构同步结构。


















