bigywater.tech
Java · 229

Phaser:可动态加入的分阶段协作器

Phaser 是 CyclicBarrier 与 CountDownLatch 的泛化:参与方可以动态增减,阶段数可以无限。这篇逐项真实运行它的阶段推进、终止、动态注册、超时与中断的行为,并测分层 Phaser 的开销。

-2147483645
终止后 getPhase 的值(3 + Integer.MIN_VALUE)
不受影响
Phaser 等待超时或被中断后的状态(CyclicBarrier 会变成 broken)
179 vs 178 μs
64 线程每轮:平铺 vs 分层 Phaser

阶段推进、onAdvance 与终止

实测 · 本机执行输出
  初始:getPhase = 0,getRegisteredParties = 3,getArrivedParties = 0,getUnarrivedParties = 3
  3 个线程各调用 arriveAndAwaitAdvance 4 次,每次的返回值(= 到达后进入的新阶段号):{worker0=[1, 2, -2147483645, -2147483645], worker1=[1, 2, -2147483645, -2147483645], worker2=[1, 2, 3, -2147483645]}
  onAdvance 被调用:[onAdvance(phase=0, parties=3), onAdvance(phase=1, parties=3), onAdvance(phase=2, parties=3)]
  最后:isTerminated = true,getPhase = -2147483645(终止后阶段号变成负数:原阶段号 + Integer.MIN_VALUE),getRegisteredParties = 3
  第 3 阶段(phase=2)的 onAdvance 返回 true → 终止;之后线程再调用 arriveAndAwaitAdvance 立刻返回负数,不再等待:-2147483645

动态注册与注销

实测 · 本机执行输出
  主线程注册了 1 方;启动 2 个工作线程,各自 register() 加入
  注册之后 getRegisteredParties = 3
  worker1 到达阶段 0
  worker0 到达阶段 0
    [onAdvance] phase=0 结束,注册方 3
  主线程推进到阶段 1,注册方 3
  worker0 到达阶段 1
  worker0 arriveAndDeregister → 注册方 2
  worker1 到达阶段 1
    [onAdvance] phase=1 结束,注册方 2
  主线程推进到阶段 2,注册方 2
  worker1 到达阶段 2
    [onAdvance] phase=2 结束,注册方 1
  worker1 arriveAndDeregister → 注册方 1
  主线程推进到阶段 3,注册方 1
    [onAdvance] phase=3 结束,注册方 0
  主线程退出循环(只剩主线程一方),arriveAndDeregister → 3;isTerminated = true
  new Phaser() 没有注册方:getRegisteredParties = 0,arrive() 抛异常吗:IllegalStateException: Attempted arrival of unregistered party for java.util.concurrent.Phaser@3764951d[phase = 0 parties = 0 arrived = 0]
  注册方全部 arriveAndDeregister 之后,默认 onAdvance(parties == 0 返回 true)→ isTerminated = true
  1 个注册方连续 arrive 三次(不等待):getPhase = 3(每次都推进了一个阶段)

超时、中断与 CyclicBarrier 的对比

实测 · 本机执行输出
  Phaser:等待超时 → TimeoutException(耗时 210 ms);之后 getPhase = 0,getArrivedParties = 0,isTerminated = false(phaser 状态不受影响)
  CyclicBarrier:await(200ms) 超时 → TimeoutException;之后 isBroken = true,另一方再 await → BrokenBarrierException
  Phaser:线程被中断 → InterruptedException;phaser 之后 isTerminated = false,getArrivedParties = 0
  CyclicBarrier:await 被中断 → InterruptedException;isBroken = true
  awaitAdvance(phase) 不到达:等到别人推进后返回新阶段号 1
  awaitAdvance 传入过期的阶段号:当前阶段 0,awaitAdvance(5) 立刻返回 0
  forceTermination 之后:isTerminated = true,arriveAndAwaitAdvance 返回 -2147483648

分层 Phaser

实测 · 本机执行输出
  flat           64 个线程 × 30000 轮:5418 ms,每轮 180.6 μs
  tiered(每组 16)  64 个线程 × 30000 轮:5334 ms,每轮 177.8 μs
  flat           64 个线程 × 30000 轮:5360 ms,每轮 178.7 μs
  tiered(每组 16)  64 个线程 × 30000 轮:5324 ms,每轮 177.5 μs
  flat           64 个线程 × 30000 轮:5315 ms,每轮 177.2 μs
  tiered(每组 16)  64 个线程 × 30000 轮:5415 ms,每轮 180.5 μs
  CPU 核数 = 10(线程数 64 远多于核数,每轮的耗时主要是线程唤醒调度)

分步演示

Phaser
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12,10 核 macOS(Apple Silicon)
    • 没有验证:Phaser 数量更多、线程数不超过核数时分层的收益(这次线程多于核数,没有测到差别);虚拟线程下的表现;与 Exchanger/CompletableFuture 的组合;Phaser 树的内部状态编码;耗时数字是单机少量测量
    京ICP备2026067502号-1京公网安备11010502063487号