在Java并发编程中,线程同步是协调多个线程执行顺序、保证数据一致性的核心操作,Phaser是JDK1.7之后引入的同步工具,适用于多阶段、动态参与线程数的同步场景,比CountDownLatch、CyclicBarrier更加灵活。下面我们来看如何在Java中使用Phaser实现线程同步。

Phaser核心原理
Phaser的核心是阶段(phase)和注册线程数(parties)两个概念。阶段是一个从0开始的整数,每完成一轮同步,阶段数会自动加1。注册线程数表示参与当前阶段同步的线程数量,当所有注册的线程都到达当前阶段的同步点时,Phaser会触发阶段推进,所有等待的线程恢复执行。
Phaser支持动态调整注册线程数,线程可以在运行过程中注册到Phaser,也可以取消注册,非常适合线程数量不确定的同步场景。
Phaser常用方法
| 方法名 | 作用说明 |
|---|---|
| register() | 向Phaser注册一个新线程,参与后续阶段的同步 |
| arrive() | 当前线程到达当前阶段的同步点,不会阻塞等待其他线程 |
| arriveAndAwaitAdvance() | 当前线程到达同步点,并且阻塞等待其他所有注册线程都到达,才继续执行 |
| arriveAndDeregister() | 当前线程到达同步点,并且取消注册,不再参与后续阶段同步 |
| getPhase() | 获取当前Phaser所处的阶段数 |
Phaser实现线程同步示例
下面通过一个多阶段任务同步的例子,演示Phaser的使用方式,三个工作线程需要分三个阶段完成任务,每个阶段都需要所有线程完成当前阶段工作后才能进入下一阶段。
import java.util.concurrent.Phaser;
public class PhaserSyncDemo {
// 创建Phaser,初始注册3个线程
private static final Phaser phaser = new Phaser(3);
static class Worker implements Runnable {
private final String name;
public Worker(String name) {
this.name = name;
}
@Override
public void run() {
try {
// 第一阶段任务
System.out.println(name + " 开始执行第一阶段任务");
Thread.sleep(1000);
System.out.println(name + " 完成第一阶段任务,当前阶段:" + phaser.getPhase());
// 到达同步点,等待其他线程完成第一阶段
phaser.arriveAndAwaitAdvance();
// 第二阶段任务
System.out.println(name + " 开始执行第二阶段任务");
Thread.sleep(1000);
System.out.println(name + " 完成第二阶段任务,当前阶段:" + phaser.getPhase());
// 到达同步点,等待其他线程完成第二阶段
phaser.arriveAndAwaitAdvance();
// 第三阶段任务
System.out.println(name + " 开始执行第三阶段任务");
Thread.sleep(1000);
System.out.println(name + " 完成第三阶段任务,当前阶段:" + phaser.getPhase());
// 到达同步点,等待其他线程完成第三阶段
phaser.arriveAndAwaitAdvance();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public static void main(String[] args) {
new Thread(new Worker("线程A")).start();
new Thread(new Worker("线程B")).start();
new Thread(new Worker("线程C")).start();
}
}运行上述代码可以看到,三个线程会先一起完成第一阶段任务,然后一起进入第二阶段,再一起进入第三阶段,实现了多阶段的线程同步。如果需要动态调整参与线程数,比如在某个阶段新增线程,可以在新增线程中调用phaser.register()方法注册,即可参与后续阶段的同步。
Phaser与其他同步器的区别
- 相比CountDownLatch:CountDownLatch的计数器无法重置,且参与者数量固定,Phaser支持阶段重复推进,参与者数量可动态调整。
- 相比CyclicBarrier:CyclicBarrier只能用于固定数量的线程同步,且只有一轮同步后重置的功能,Phaser支持多阶段、动态参与者的场景。
在实际开发中,如果遇到多阶段同步、线程数量动态变化的场景,优先选择Phaser实现线程同步,能获得更好的灵活性。