Phaser支持动态线程注册与注销,通过arriveAndAwaitAdvance实现多阶段同步,适用于需分轮次协同执行的并发场景。

在Java并发编程中,Phaser 是一个灵活且强大的同步工具,适用于需要多线程分阶段协作执行的场景。相比 CountDownLatch 和 CyclicBarrier,Phaser 更加动态,支持线程的动态注册与注销,并能实现循环执行多个 Phase(阶段)。它特别适合用于模拟周期性任务、游戏帧更新、并行算法迭代等需要“每轮等待所有线程完成后再进入下一轮”的情况。
理解 Phaser 的基本机制
Phaser 的核心是阶段(Phase)的概念。每个阶段开始时,所有参与线程必须调用 arriveAndAwaitAdvance() 方法进行同步。当所有注册的线程都到达后,Phaser 自动进入下一阶段(phase + 1),并唤醒所有等待线程。若某阶段返回值为负数,则表示 Phaser 已终止。
关键方法包括:
- arriveAndAwaitAdvance():线程到达当前阶段并等待其他线程完成
- register():动态增加一个参与线程(适用于运行中加入)
- arriveAndDeregister():到达并退出同步(不再参与后续阶段)
- getPhase():获取当前阶段编号(从0开始递增)
实现线程循环执行的典型模式
要让多个线程协同完成多轮循环任务,可以使用以下结构:
立即学习“Java免费学习笔记(深入)”;
定义一个 Runnable 任务,在其 run() 方法中持续调用 arriveAndAwaitAdvance(),直到满足退出条件。
示例代码:
Phaser phaser = new Phaser(3); // 初始注册3个线程
for (int i = 0; i < 3; i++) {
new Thread(() -> {
int phase = 0;
while (phase < 3) { // 执行3轮
System.out.println(Thread.currentThread().getName() +
" 正在执行第 " + phase + " 阶段任务");
// 模拟工作
try { Thread.sleep(500); } catch (InterruptedException e) {}
// 同步点:等待所有线程完成当前阶段
phase = phaser.arriveAndAwaitAdvance();
// phase 返回的是进入的新阶段号
}
System.out.println(Thread.currentThread().getName() + " 完成所有阶段");
}).start();
}
在这个例子中,三个线程会同步执行0、1、2三个阶段。每次调用 arriveAndAwaitAdvance() 都会阻塞直到其他线程也到达,然后共同进入下一阶段。
动态控制线程生命周期和阶段数量
Phaser 的优势之一是支持运行时动态调整参与线程数。比如某些线程只需参与前几个阶段。
示例:部分线程中途退出
Phaser phaser = new Phaser();
phaser.register(); // 主线程也参与
Runnable worker = () -> {
for (int i = 0; i < 2; i++) {
System.out.println(Thread.currentThread().getName() + " 执行阶段 " + i);
try { Thread.sleep(400); } catch (InterruptedException e) {}
int nextPhase = phaser.arriveAndAwaitAdvance();
if (nextPhase >= 2) break; // 超过第2阶段就不再继续
}
phaser.arriveAndDeregister(); // 完成后注销自己
};
new Thread(worker).start();
new Thread(worker).start();
// 主线程等待前两个阶段完成后终止 Phaser
phaser.arriveAndAwaitAdvance(); // 阶段0
phaser.arriveAndAwaitAdvance(); // 阶段1
phaser.forceTermination(); // 终止,避免其他线程无限等待
这里通过 arriveAndDeregister() 让线程在完成指定阶段后自动退出,主线程则通过 forceTermination() 强制结束 Phaser,防止资源泄漏。
实际应用中的注意事项
使用 Phaser 进行循环控制时,有几个实践要点需要注意:
- 确保每个线程对 arrive 和 deregister 的调用次数匹配,避免计数错误导致死锁
- 合理设置初始参与者数量,或通过 register() 动态添加
- 监控 getPhase() 值来判断当前所处阶段,可用于日志或状态追踪
- 长时间运行的循环应考虑中断处理,响应 Thread.interrupted()
- 避免在 arriveAndAwaitAdvance() 中执行耗时操作,影响整体同步效率
对于需要精确控制迭代次数的批处理系统,Phaser 提供了比 CyclicBarrier 更细粒度的控制能力,尤其是在各线程迭代次数不一致的场景下表现更优。
基本上就这些。Phaser 在设计多阶段并行任务时非常实用,只要掌握好注册、同步和注销的节奏,就能高效实现复杂的线程协调逻辑。










