CyclicBarrier未直接使用AQS,而是基于ReentrantLock+Condition自主实现;其核心用volatile int count管理状态,通过lock保证临界区、condition.await()挂起线程、signalAll唤醒全部线程,并自行处理中断、超时与重置。

CyclicBarrier 本身不直接使用 AQS(AbstractQueuedSynchronizer)作为底层实现,而是基于 ReentrantLock + Condition 自主构建等待队列和唤醒机制。 它和 AQS 没有继承或组合关系,但设计思想与 AQS 高度相似——比如状态管理、线程阻塞/唤醒、公平性控制等。理解它如何“绕开 AQS 却做着类似的事”,才是关键。
核心状态用 int 类型原子维护
CyclicBarrier 内部用一个 private int count 记录还需到达的线程数,初始值为 parties(参与方总数)。每次 await() 调用成功,count 就减 1。当 count 减到 0,说明所有线程已就位,触发屏障动作(如执行 barrierAction),然后重置 count 为 parties,进入下一轮循环。
这个 count 的更新不是靠 AQS 的 state 字段,而是靠 ReentrantLock 配合 CAS 式的 tryLock + compareAndSet 模拟:实际是用 lock.lock() 保证临界区,再用普通 volatile int 更新,配合 condition.await() 实现等待。
等待队列靠 Condition 实现,而非 AQS 的 CLH 队列
CyclicBarrier 内部持有一个 ReentrantLock lock 和一个 Condition trip(名字取自“trip the barrier”)。线程调用 await() 时:
立即学习“Java免费学习笔记(深入)”;
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 先加锁,检查是否已打破(broken)、是否已完成(count == 0)、是否超时等
- 若需等待,调用 trip.await() —— 这会把当前线程挂起,并加入 Condition 关联的等待队列(由 AQS 的 ConditionObject 维护)
- 当最后一个线程到达并调用 trip.signalAll(),所有在该 Condition 上等待的线程被唤醒,重新竞争 lock,继续执行后续逻辑
注意:这里的 Condition 是 AQS 提供的,但 CyclicBarrier 并未直接复用 AQS 的独占/共享同步逻辑;它只是借用了 Condition 的等待/通知能力,同步控制仍由自己封装。
中断、超时、重置等行为全部自行处理
AQS 提供了标准的中断响应(acquireInterruptibly)、超时获取(tryAcquireNanos)模板,但 CyclicBarrier 没走这些路径。它自己实现:
- await() 中检测 Thread.interrupted(),抛出 InterruptedException
- 带超时的 await(long, TimeUnit) 用的是 lock.tryLock(timeout),失败则主动清理并返回 false
- reset() 方法手动将 count 重置、标记 broken、signalAll 唤醒所有等待者 —— 这些都是显式调用 lock 和 condition 的结果
也就是说,CyclicBarrier 把“同步协调”的职责全揽下来,AQS 只是它工具箱里的一把螺丝刀(用于 Condition),而不是整台发动机。
为什么没用 AQS 直接实现?
因为 CyclicBarrier 的语义更接近“多线程集体等待+一次性广播唤醒”,不是典型的独占/共享资源竞争模型:
- 不需要支持“尝试获取”“可取消等待”等 AQS 标准接口的细粒度控制
- 需要频繁重置状态、支持重复使用,而 AQS 的 state 是单向递进设计(虽可重置,但非原生目标)
- 内置 barrierAction 回调、broken 状态管理等业务逻辑太重,硬套 AQS 模板反而臃肿
所以 Doug Lea 选择用更轻量、更可控的 Lock + Condition 组合,既利用了 AQS 的成熟等待队列(通过 ConditionObject),又保持了上层逻辑的清晰和灵活。

















