You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中使用Phaser实现线程同步的错误用法排查

Phaser实现线程顺序同步的错误用法分析

测试代码

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class FooRunner {
  public static void main(String[] args) {

    Foo foo = new Foo();
    ExecutorService executors = Executors.newFixedThreadPool(3);
    Runnable first =
        () -> {
          try {
            foo.first(() -> System.out.println("first"));
          } catch (InterruptedException e) {
            throw new RuntimeException(e);
          }
        };

    Runnable second =
        () -> {
          try {
            foo.second(() -> System.out.println("second"));
          } catch (InterruptedException e) {
            throw new RuntimeException(e);
          }
        };
    Runnable third =
        () -> {
          try {
            foo.third(() -> System.out.println("third"));
          } catch (InterruptedException e) {
            throw new RuntimeException(e);
          }
        };

    executors.submit(third);
    executors.submit(first);
    executors.submit(second);

    executors.shutdown();
  }
}

基于Phaser的同步实现代码

import java.util.concurrent.Phaser;

public class Foo {

  private final Phaser phaser = new Phaser(1);

  public Foo() {}

  public void first(Runnable printFirst) throws InterruptedException {
    printFirst.run();
    phaser.arriveAndAwaitAdvance();
  }

  public void second(Runnable printSecond) throws InterruptedException {
    phaser.awaitAdvance(1); // 等待first完成
    printSecond.run();
    phaser.arriveAndAwaitAdvance();
  }

  public void third(Runnable printThird) throws InterruptedException {
    phaser.awaitAdvance(2); // 等待second完成
    printThird.run();
    phaser.arriveAndAwaitAdvance();
  }
}

预期输出

first
second
third

问题

但实际线程并未在Phaser上等待,请问当前的Phaser实现是否属于错误用法?


回答

当前的Phaser实现确实是错误用法,核心问题在于对Phaser的阶段同步逻辑理解有误:

  1. 阶段推进逻辑不匹配顺序同步需求
    Phaser初始化时指定了1个参与者,first方法调用arriveAndAwaitAdvance()时,仅有的1个参与者已到达,阶段会直接从0推进到1,方法立即返回,不会等待任何其他线程。这导致first执行后没有阻塞,无法保证后续线程的执行顺序。

  2. awaitAdvance方法使用逻辑错误
    awaitAdvance(int phase)的作用是等待Phaser的阶段号大于传入值,若当前阶段号已满足条件则直接返回:

    • 若first先执行完成,阶段号变为1,second中的awaitAdvance(1)会直接返回,不会等待;
    • 若second先执行,阶段号还是0,awaitAdvance(1)会进入等待,但这只是偶然阻塞,并非可靠的顺序保证;
    • third中的awaitAdvance(2)同理,依赖阶段号的方式无法稳定实现线程顺序执行。

另外需要明确:Phaser并非实现线程顺序同步的合适选择,它的设计目标是支持多线程分阶段协同工作(所有线程完成当前阶段后,再一起进入下一阶段),而非保证线程按固定顺序依次执行。


Phaser典型使用示例

Phaser phaser = new Phaser(4); // 3个工作线程 + 主线程作为参与者

for (int i = 0; i < 3; i++) {
    new Thread(
            () -> {
                try {
                    System.out.println(
                        "线程" + Thread.currentThread().getName() + "等待进入第一阶段");
                    phaser.arriveAndAwaitAdvance(); // 等待所有参与者到达第一阶段

                    Thread.sleep(Duration.ofSeconds(10));
                    System.out.println("线程" + Thread.currentThread().getName() + "准备进入第二阶段");
                    // 第二阶段
                    phaser.arriveAndAwaitAdvance(); // 等待所有参与者到达第二阶段
                } catch (Exception e) {
                    e.printStackTrace();
                }
            })
        .start();
}

phaser.arriveAndDeregister(); // 主线程完成任务,注销自己作为参与者

内容的提问来源于stack exchange,提问作者sinsuren

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 02:25:14