CyclicBarrier 是 Java 并发包中可重用的线程同步辅助类,用于多个线程在屏障点相互等待并一起继续执行;其内部基于 ReentrantLock 和 Condition 实现计数器减至零后唤醒所有线程,并自动重置计数器以支持循环使用。

CyclicBarrier 是 Java 并发包(java.util.concurrent)中用于线程协作的同步辅助类,适用于多个线程相互等待、到达某个“屏障点”后**一起继续执行**的场景。它和 CountDownLatch 不同:CyclicBarrier 可重用(可循环),且所有线程都需主动调用 await() 才能触发释放;而 CountDownLatch 通常由一个或多个线程调用 countDown() 来触发释放。
核心机制:怎么让线程在栅栏处“等齐”?
CyclicBarrier 内部维护一个计数器(初始值为参与线程数),每个线程调用 await() 时:
- 计数器减 1;
- 若减到 0,说明所有线程都已到达,栅栏“打开”,所有等待线程被唤醒并继续执行;
- 否则当前线程进入等待状态(底层基于 ReentrantLock + Condition 实现)。
一旦触发释放,计数器会自动重置(这就是“Cyclic”的由来),下次可再次使用。
基本用法:创建与 await() 调用
构造方式有两种:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
new CyclicBarrier(int parties):指定需要等待的线程数; -
new CyclicBarrier(int parties, Runnable barrierAction):额外指定一个“屏障动作”——当最后一个线程到达时、所有线程被释放前,由该线程(通常是最后一个调用await()的线程)执行一次,常用于汇总结果、日志记录等。
每个协作线程必须在关键位置调用 await(),该方法可能抛出:
- InterruptedException(线程被中断);
- BrokenBarrierException(栅栏已被破坏,如某线程超时或被中断导致栅栏无法正常开启)。
实战示例:4 个线程模拟并发任务,每轮计算后同步汇总
(简化版,无异常全处理,仅展示协作逻辑)import java.util.concurrent.CyclicBarrier;
<p>public class CyclicBarrierDemo {
private static final int THREAD_COUNT = 4;
private static final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT, () -> {
System.out.println("✅ 所有线程完成本轮计算,开始汇总...");
// 这里可做合并、打印、写库等操作
});</p><pre class="brush:php;toolbar:false;">public static void main(String[] args) {
for (int i = 0; i < THREAD_COUNT; i++) {
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + " 开始执行任务");
Thread.sleep((long) (Math.random() * 2000)); // 模拟耗时差异
System.out.println(Thread.currentThread().getName() + " 完成计算");
barrier.await(); // 到达栅栏,等待其他线程
System.out.println(Thread.currentThread().getName() + " 继续后续流程(如读取汇总结果)");
} catch (Exception e) {
e.printStackTrace();
}
}, "Worker-" + i).start();
}
}
}
立即学习“Java免费学习笔记(深入)”;
运行效果类似:
- Worker-0、Worker-1、Worker-2 先打印“完成计算”,但卡在
await(); - Worker-3 最后到达 → 触发屏障动作 → 所有线程继续执行下一句;
- 下一轮如果复用该 barrier(比如放在循环里),仍可再次等待齐备。
注意事项与常见问题
- 线程安全:CyclicBarrier 本身是线程安全的,无需额外同步;
-
超时控制:可用
await(long timeout, TimeUnit unit)避免永久阻塞,超时会抛TimeoutException并使栅栏进入破损状态; -
破损状态(broken):任一等待线程被中断、超时或 await 抛异常,栅栏即变 broken,后续所有 await 都立即抛
BrokenBarrierException;可通过isBroken()查询,用reset()强制重置(慎用,需确保无线程正在 await); - 不要在 barrierAction 中做耗时或阻塞操作:它由最后一个到达线程串行执行,会拖慢全体释放速度。

















