Phaser 是 Java 并发包(java.util.concurrent)中的一种多阶段同步工具,专为协调多个线程分阶段执行任务而设计。它结合了 CyclicBarrier 和 CountDownLatch 的功能,并支持动态调整参与者数量、多阶段同步等高级特性。以下是其全面解析:
🔧 一、基本原理
1. 核心机制
- 多阶段同步
Phaser 将任务划分为多个阶段(Phase),每个阶段结束时所有线程需同步,之后才能进入下一阶段。阶段号从0开始递增,直至终止。 - 动态参与者管理
线程可通过register()动态注册为参与者,或通过arriveAndDeregister()注销,无需在初始化时固定线程数量。 - 状态维护
内部使用AtomicLong存储状态,包含:- 当前阶段号(高 32 位)
- 已注册参与者数(中 16 位)
- 未到达参与者数(低 16 位)。
2. 关键操作
- 到达与等待
arriveAndAwaitAdvance():线程完成任务后等待其他参与者到达,全部到达后自动推进阶段。 - 终止条件
重写onAdvance(int phase, int parties)可自定义阶段结束行为(如数据汇总)。返回true时 Phaser 终止。
🛠️ 二、核心特性
| 特性 | 说明 |
|---|---|
| 多阶段同步 | 支持无限阶段循环,每个阶段需所有线程到达屏障点。 |
| 动态线程管理 | 运行时增减参与者,适用线程数量不确定的场景。 |
| 可重用性 | 阶段自动重置,无需手动重置(如 CyclicBarrier)。 |
| 分层结构 | 支持父子 Phaser 树,用于分布式任务协调。 |
💻 三、使用方法与代码示例
1. 基础用法:三阶段任务同步
import java.util.concurrent.Phaser;
public class PhaserDemo {
public static void main(String[] args) {
Phaser phaser = new Phaser(3); // 初始注册3个参与者
for (int i = 0; i < 3; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 完成阶段1");
phaser.arriveAndAwaitAdvance(); // 同步点1
System.out.println(Thread.currentThread().getName() + " 完成阶段2");
phaser.arriveAndAwaitAdvance(); // 同步点2
System.out.println(Thread.currentThread().getName() + " 完成阶段3");
phaser.arriveAndDeregister(); // 注销并推进
}).start();
}
}
}
输出:
Thread-0 完成阶段1
Thread-1 完成阶段1
Thread-2 完成阶段1
Thread-0 完成阶段2
Thread-1 完成阶段2
Thread-2 完成阶段2
...
说明:所有线程需在每个阶段同步后才能继续。
2. 动态任务注册:批量数据处理
class BatchProcessor implements Runnable {
private final Phaser phaser;
private final List<String> data;
BatchProcessor(Phaser phaser, List<String> data) {
this.phaser = phaser;
this.data = data;
phaser.register(); // 动态注册新参与者
}
@Override
public void run() {
while (!data.isEmpty()) {
processBatch(data.subList(0, Math.min(10, data.size())));
phaser.arriveAndAwaitAdvance(); // 等待其他批次完成
}
phaser.arriveAndDeregister(); // 处理完毕,注销
}
private void processBatch(List<String> batch) {
// 处理数据...
}
}
适用场景:数据分批次处理,线程数随任务动态调整。
3. 自定义阶段回调
Phaser phaser = new Phaser(3) {
@Override
protected boolean onAdvance(int phase, int parties) {
System.out.println("阶段 " + phase + " 完成,参与线程数: " + parties);
return phase >= 2; // 执行3个阶段后终止
}
};
说明:每个阶段结束时触发自定义逻辑(如日志、资源释放)。
⚖️ 四、优缺点分析
| 维度 | 优点 | 缺点 |
|---|---|---|
| 灵活性 | 支持动态增减参与者、多阶段同步。 | 学习曲线陡峭:API 复杂于 CyclicBarrier。 |
| 可扩展性 | 适合大规模并发任务(如千人游戏房间)。 | 性能开销:状态维护和 CAS 操作在高并发下可能成为瓶颈。 |
| 功能强大 | 支持分层、自定义终止条件、超时控制。 | 不适用简单场景:单阶段或固定线程数时,CountDownLatch 更简单。 |
🎯 五、适用场景
- 多阶段并行计算
- 示例:分治算法(如归并排序),每阶段需子任务全部完成。
- 动态任务流水线
- 示例:爬虫系统,线程根据任务量动态加入/退出。
- 游戏或模拟系统
- 示例:多玩家回合制游戏,每回合需所有玩家操作完毕。
- 批量数据处理
- 示例:ETL 任务分批次执行,批次间需同步。
💎 六、总结
- 核心价值:通过多阶段同步和动态参与者管理,解决复杂并发任务的协调问题。
- 使用原则:
- 优先用于多阶段、线程数动态变化的场景。
- 避免在单阶段或固定线程数的简单场景中使用(改用
CountDownLatch或CyclicBarrier)。 - 通过
onAdvance()实现阶段回调,提升代码可维护性。
- 性能提示:监控阶段推进时间,避免因个别线程延迟导致整体卡顿。
通过合理应用 Phaser,可在游戏开发、分布式计算、流水线处理等场景中实现高效、灵活的多线程协作 🔥。建议结合源码(如
Phaser.state的位操作)深入理解其实现细节。
458

被折叠的 条评论
为什么被折叠?



