Phaser 分段相位屏障(高级CyclicBarrier+CountDownLatch合体)
一、核心定位
Phaser = 增强版同步屏障,融合了 CountDownLatch(计数等待)+ CyclicBarrier(可复用分批等待),解决二者短板:
- CyclicBarrier:参与者数量创建时固定,不能动态增减;只支持单阶段等待;
- CountDownLatch:一次性,计数归零不可复用;
- Phaser 优势:
- 参与者(注册线程)动态注册/注销,运行时增减;
- 多阶段(phase)分段执行,每阶段全部线程抵达才进入下一阶段;
- 可复用,支持分批次多轮任务;
- 支持主动退出、批量等待、阶段回调;
底层同样基于AQS实现。
二、核心核心术语
- Participant 参与者
参与屏障的线程,register()注册,arriveAndDeregister()注销;可随时新增/减少。 - Phase 相位/阶段
Phaser 内置自增阶段编号:0 → 1 → 2 ……
所有参与者完成当前阶段,才自动切换到下一阶段。 - arrive:抵达
线程完成当前阶段任务,告知Phaser“我干完了”,分两种API:arriveAndAwaitAdvance():抵达后阻塞,等所有人抵达再进下一阶段(最常用)arrive():仅标记抵达,不阻塞,适合主线程汇总arriveAndDeregister():抵达后注销自己,不再参与后续阶段
三、关键API分类
1. 注册参与者(新增线程)
int register(); // 注册1个参与者,返回当前阶段号
int bulkRegister(int parties); // 批量注册N个参与者
2. 阶段抵达核心方法(线程完成当前任务调用)
// 1. 抵达并阻塞,等全部参与者完成,再进入下一阶段【业务最常用】
int arriveAndAwaitAdvance();
// 2. 仅标记抵达,不阻塞,不等待其他线程
int arrive();
// 3. 抵达后注销自己,不再参与后续所有阶段
int arriveAndDeregister();
3. 主动等待阶段(主线程专用)
// 等待指定阶段完成,阻塞主线程
boolean awaitAdvance(int phase);
// 限时等待阶段完成
boolean awaitAdvanceInterruptibly(int phase, long timeout, TimeUnit unit);
4. 阶段回调钩子(可选重写)
// 每一个阶段全部线程抵达后,自动执行,返回true则终止Phaser
protected boolean onAdvance(int phase, int registeredParties)
- phase:当前完成的阶段编号
- registeredParties:当前剩余注册总线程数
- 返回
true:Phaser直接终止,所有await线程立即返回;返回false:正常切换下一阶段
四、经典示例:三阶段批处理(读取→解析→入库)
场景:3个工作线程,分3阶段执行,每阶段全部线程完成再走下一阶段
import java.util.concurrent.Phaser;
public class PhaserStageDemo {
public static void main(String[] args) throws InterruptedException {
// 自定义Phaser,重写阶段完成回调
Phaser phaser = new Phaser() {
// 所有线程完成当前阶段后触发
@Override
protected boolean onAdvance(int phase, int registeredParties) {
System.out.println("===== 阶段" + phase + "全部完成,当前注册线程数:" + registeredParties + " =====");
// 一共3个阶段 0/1/2,阶段2完成后终止Phaser
return phase >= 2 || registeredParties == 0;
}
};
// 注册3个工作线程
int threadNum = 3;
phaser.bulkRegister(threadNum);
for (int i = 0; i < threadNum; i++) {
new Thread(() -> {
String name = Thread.currentThread().getName();
try {
// ========== 阶段0:读取文件 ==========
System.out.println(name + " 阶段0:读取数据");
Thread.sleep(200);
// 抵达,阻塞等待所有人读完
phaser.arriveAndAwaitAdvance();
// ========== 阶段1:解析数据 ==========
System.out.println(name + " 阶段1:解析数据");
Thread.sleep(300);
phaser.arriveAndAwaitAdvance();
// ========== 阶段2:入库存储 ==========
System.out.println(name + " 阶段2:写入数据库");
Thread.sleep(100);
// 完成所有阶段,注销自身,不再参与后续
phaser.arriveAndDeregister();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}, "线程-" + i).start();
}
// 主线程等待整个Phaser全部执行完毕
while (!phaser.isTerminated()) {
Thread.sleep(100);
}
System.out.println("所有阶段任务全部结束,Phaser已终止");
}
}
执行流程说明
- 所有线程并行执行阶段0读取,各自调用
arriveAndAwaitAdvance()阻塞; - 3个线程全部抵达后,触发
onAdvance(0,3),自动切换到阶段1; - 所有线程同时放行,并行执行阶段1解析,再次阻塞等待全员抵达;
- 阶段1全部完成,触发回调,切换阶段2;
- 阶段2入库完成后,调用
arriveAndDeregister()注销线程; - 3个线程全部注销,
registeredParties=0,onAdvance返回true,Phaser终止。
五、动态增减参与者示例(CyclicBarrier做不到)
CyclicBarrier创建时固定线程数,运行中无法新增;Phaser支持中途register新增线程:
Phaser phaser = new Phaser(2); // 初始2个线程
// 原有2线程执行阶段0...
// 运行中途新增1个参与者
phaser.register();
六、Phaser vs CyclicBarrier vs CountDownLatch 核心对比
| 特性 | CountDownLatch | CyclicBarrier | Phaser |
|---|---|---|---|
| 参与者数量 | 固定,创建指定 | 固定,创建指定 | 动态,运行时注册/注销 |
| 复用性 | 一次性,不可重置 | 可循环复用,单阶段 | 无限复用,多阶段分段 |
| 多阶段支持 | 不支持 | 仅单阶段 | 原生多阶段流水线 |
| 线程退出 | 无法主动注销 | 不能退出 | arriveAndDeregister主动注销 |
| 完成回调 | 无 | 屏障回调(仅一次) | 每阶段完成均可回调onAdvance |
| 使用场景 | 主线程等待多任务结束、双Latch压测 | 多线程互相等待,分批并行计算 | 多阶段流水线、动态任务、复杂分段同步 |
七、典型业务落地场景
- 多阶段流水线任务
文件处理:读取 → 清洗 → 计算 → 入库;每一步全部线程完成再进入下一环节。 - 动态分片并行计算
运行中根据数据量新增/减少处理线程,CyclicBarrier无法实现。 - 多轮次批量任务
循环多批次处理数据,每批次分多个执行阶段。 - 多线程分步初始化
微服务多组件分阶段启动,阶段1加载配置、阶段2初始化连接池、阶段3对外提供服务。
八、高频易错点
- 忘记调用arriveXXX方法
线程执行完阶段逻辑不调用抵达方法,Phaser永远无法推进阶段,所有线程阻塞死锁。 - 混淆arrive() 和 arriveAndAwaitAdvance()
arrive()仅标记抵达,不会阻塞;子线程必须用arriveAndAwaitAdvance等待其他线程。 - onAdvance返回值控制终止
如果不控制终止条件,Phaser会无限循环阶段0、1、2、3…,不会自动结束。 - 并发注册线程注意线程安全
register/bulkRegister是线程安全方法,多线程同时新增参与者无并发问题。 - 终止后不可复用
isTerminated()=true屏障彻底失效,无法再次使用,需要新建Phaser。
九、极简使用总结
- 固定N线程、单阶段循环同步 → CyclicBarrier;
- 一次性等待所有任务完成 → CountDownLatch;
- 多阶段流水线 / 动态增减线程 → 优先Phaser。
百流积聚,江河是也;文若化风,可以砾石。

浙公网安备 33010602011771号