phaser基于位运算状态压缩实现,非aqs;其volatile long state字段分三段:低16位存unarrived数,中16位存registeredparties,高32位存phase编号,通过原子cas更新实现无锁、轻量、动态的多阶段同步。

Phaser 不是基于 AQS 实现的,它用的是更底层、更紧凑的位运算状态压缩机制——把 phase(阶段号)、registeredParties(已注册人数)、arrivedParties(已到达人数)全塞进一个 long 型 state 变量里。
state 字段怎么装下三个关键数?
Java 的 Phaser 内部只维护一个 volatile long state,没有独立的 phase 变量、parties 变量或 arrived 变量。它靠位域划分来复用存储:
- 低 16 位(0–15):记录当前 unarrived 数(即还差几人到齐)
- 中间 16 位(16–31):记录 registeredParties(本阶段应到总人数)
- 高 32 位(32–63):存放 phase 编号(从 0 开始,最大到 Integer.MAX_VALUE,溢出后归 0)
比如 state = 0x0000_0003_0003_0000L,表示 phase=3、registered=3、unarrived=0 —— 恰好全员到齐,可推进下一阶段。
每次 arrive 都在做原子位更新
调用 arrive() 或 arriveAndAwaitAdvance() 时,Phaser 不是简单地 ++arrived,而是执行一次 CAS 修改 state:
- 先读取当前 state
- 检查 unarrived 是否 > 0;若为 0,说明已满,不修改直接返回当前 phase
- 若未满,则尝试用 CAS 将 unarrived 减 1(即 state - 1)
- 若 CAS 成功,本次到达生效;失败则重试
这个过程完全无锁、无对象分配、无队列节点创建,比 AQS 的 Node 入队轻量得多。
phase 推进不是“加一”,而是“状态跃迁”
当 unarrived 减到 0,Phaser 并不会立刻 +1 phase,而是触发一次状态跃迁(advance):
- 把当前 state 的高 32 位 phase +1(带溢出处理)
- 把中间 16 位 registeredParties 按需保留(如未 deregister,就复用原值)
- 把低 16 位 unarrived 重置为 registeredParties(即新阶段又需要全员重新到达)
- 这个新 state 仍通过一次 CAS 写入,成功后唤醒所有等待该 phase 的线程
所以 phase 不是计数器,而是 state 中一个被整体替换的字段段;推进本质是一次原子状态快照切换。
为什么不用 AQS?因为目标不同
AQS 是为“独占/共享锁语义”设计的,依赖 CLH 队列管理阻塞线程,适合长时持有资源的场景;而 Phaser 是为高频、短时、多轮、动态规模的同步点设计的:
- 不需要维护每个等待线程的 Node 节点(省内存)
- 不依赖 park/unpark 队列调度(减少 JVM 线程调度开销)
- 支持运行中增减参与者(AQS 的 wait queue 无法动态删节点)
- 阶段号本身可作为版本标记,天然支持“等待特定 phase”而非“无差别唤醒”
它更像一个并发安全的“状态机寄存器”,而不是一个“排队协调器”。










