Phaser 是 CyclicBarrier 与 CountDownLatch 的泛化:参与方可以动态增减,阶段数可以无限。这篇逐项真实运行它的阶段推进、终止、动态注册、超时与中断的行为,并测分层 Phaser 的开销。
初始: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(每次都推进了一个阶段)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
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 远多于核数,每轮的耗时主要是线程唤醒调度)