CyclicBarrier 是 Java 并发包中可重用的循环屏障工具,用于固定数量线程多轮协作同步;构造时指定参与线程数,支持屏障动作、超时等待和手动重置,适用于分阶段并行计算等场景。

CyclicBarrier 是 Java 并发包(java.util.concurrent)中用于协调多个线程在某个“屏障点”同步等待的工具。它特别适合需要**多轮重复协作**的场景,比如分阶段并行计算、模拟多玩家回合制游戏、批量任务分片处理后再汇总等。
理解 CyclicBarrier 的核心行为
与 CountDownLatch 不同,CyclicBarrier 是可重用的:一旦所有参与线程到达屏障点,它们被同时释放,屏障自动重置,可再次使用。
关键特性包括:
- 构造时指定参与线程总数(
parties),即必须有 N 个线程调用await()才能一起放行 - 可选传入一个
Runnable作为“屏障动作”,在最后第 N 个线程到达、但所有线程尚未释放前执行(常用于汇总、日志、状态检查) - 调用
await()的线程会阻塞,直到满足条件或超时/中断 - 任一线程在
await()中被中断,或等待超时,或屏障被reset(),都会导致其他已等待线程抛出BrokenBarrierException
基础用法:创建并启动带屏障的线程组
下面是一个 3 个线程协作完成 2 轮“准备 → 执行 → 汇报”的例子:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
import java.util.concurrent.*;
<p>public class CyclicBarrierExample {
public static void main(String[] args) {
// 指定 3 个线程参与,每轮结束时打印汇总信息
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("✅ 所有线程已完成本轮,开始汇总...");
});</p><pre class="brush:php;toolbar:false;"> for (int i = 0; i < 3; i++) {
int threadId = i + 1;
new Thread(() -> {
try {
System.out.println("? 线程 " + threadId + " 开始准备");
Thread.sleep(100 * threadId); // 模拟不同耗时的准备
barrier.await(); // 到达第一道屏障:等待全部准备就绪
System.out.println("? 线程 " + threadId + " 开始执行任务");
Thread.sleep(50);
barrier.await(); // 到达第二道屏障:等待全部执行完毕
System.out.println("? 线程 " + threadId + " 汇报结果");
} catch (InterruptedException | BrokenBarrierException e) {
Thread.currentThread().interrupt();
System.err.println("线程 " + threadId + " 被中断或屏障损坏:" + e.getMessage());
}
}).start();
}
}}
运行效果中你会看到:3 个线程各自准备完成后,才一起进入执行阶段;执行完又集体停顿,再一起汇报 —— 这就是“循环屏障”的典型节奏。
实用技巧与注意事项
实际开发中需注意这些细节:
-
异常必须处理:
await()抛出InterruptedException和BrokenBarrierException,忽略后者可能导致部分线程卡死或逻辑错乱 -
避免死锁风险:确保每个线程最终都会调用
await();若某线程因异常提前退出且未 await,其余线程将永远等待 -
合理设置超时:使用
await(long timeout, TimeUnit unit)防止无限等待,便于故障隔离和恢复 - 屏障动作不阻塞后续线程:屏障动作由最后一个到达的线程执行,执行完毕后所有线程才继续。因此该动作不宜耗时过长,否则拖慢整体进度
-
手动重置屏障:调用
reset()可强制打破当前等待,并让后续 await 抛出BrokenBarrierException,适用于主动终止协作流程
对比 CountDownLatch 和 Phaser 的适用场景
选择同步工具要匹配业务语义:
- 用
CyclicBarrier:需要**固定数量线程多次协同**(如每轮都等齐再动),强调“循环性”和“对等参与” - 用
CountDownLatch:适用于“一个线程等其他 N 个线程完成”,且只用一次(不可重用) - 用
Phaser:更灵活,支持动态增减参与者、分阶段注册、可查询阶段号,适合复杂多阶段协调(JDK 7+)
如果只是简单的一次性等待,优先考虑 CountDownLatch;若需反复同步且线程数稳定,CyclicBarrier 更简洁直观。


















