CyclicBarrier 是可重复使用的线程同步工具,支持在所有线程到达屏障后执行回调任务,适用于分段并行计算后的结果汇总;其 barrier action 由最后一个到达的线程执行,需避免耗时操作,且异常会导致屏障破损。

CyclicBarrier 是 Java 并发包中用于协调多个线程在某个“屏障点”同步等待的工具,特别适合“分段并行计算 → 汇总结果”的场景。它不像 CountDownLatch 那样只能用一次,而是可重复使用(cyclic),且支持在所有线程到达后执行一个回调任务(Runnable),非常适合做阶段性聚合或数据合并。
理解 CyclicBarrier 的核心行为
CyclicBarrier 构造时指定参与线程数(parties),每个线程调用 await() 进入等待;当第 parties 个线程调用 await,所有线程同时被唤醒继续执行。若设置了 barrier action(构造函数第二个参数),该 Runnable 会在最后到达的线程释放其他线程前、在该线程上下文中执行——这是合并数据的理想位置。
- 所有线程必须调用
await()才能共同越过屏障,缺一不可 - 屏障动作(barrier action)由最后一个到达的线程执行,不是新线程,因此要避免耗时或阻塞操作
- 若某线程中断或超时,整个屏障会进入破损状态(broken),后续 await 抛出 BrokenBarrierException
典型分段并行+合并的代码结构
假设你有一组待处理的数据(如 List<Integer>),想让 4 个线程各自处理一段,完成后把每段结果汇总到一个共享容器中:
- 用
new CyclicBarrier(4, () -> { /* 合并逻辑 */ })创建带合并动作的屏障 - 每个线程处理自己的数据子集,得到局部结果(如 sum、list、map 等)
- 将局部结果存入线程安全的共享结构(如 ConcurrentHashMap、CopyOnWriteArrayList),或暂存在线程本地变量中,等 barrier action 统一读取
- 在 barrier action 中遍历各线程的结果并合并(注意:此时只有最后一个线程在执行,无需额外同步)
示例关键片段:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
// 共享结果容器(线程安全)
List<Integer> partialSums = Collections.synchronizedList(new ArrayList<>());
<p>CyclicBarrier barrier = new CyclicBarrier(4, () -> {
int total = partialSums.stream().mapToInt(Integer::intValue).sum();
System.out.println("全部完成,总和:" + total);
partialSums.clear(); // 重用前清空
});</p><p>// 每个线程执行:
for (int i = start; i < end; i++) {
localSum += data.get(i);
}
partialSums.add(localSum);
barrier.await(); // 等待其他线程,触发合并如何安全传递各线程的局部结果
直接在 barrier action 中访问“谁算出了什么”需要显式关联。推荐两种方式:
-
用数组或列表按索引存储:创建长度为 parties 的 Object[] 或 AtomicReferenceArray,每个线程根据自己的序号(
barrier.getNumberWaiting() + 1不可靠,建议传入 threadId 或用 AtomicInteger 分配 id)写入结果 - 用 ThreadLocal + 全局注册表:每个线程初始化时向一个 static ConcurrentHashMap<Thread, Result> 注册自己,barrier action 遍历 map 获取全部结果(记得 remove 防止内存泄漏)
- 更简洁的做法:让每个线程把结果写入同一个线程安全集合(如 ConcurrentLinkedQueue),barrier action 一次性 drain 所有元素
注意异常与重用边界
CyclicBarrier 在 broken 状态下无法自动恢复,需调用 reset() 重置(但会唤醒所有等待线程并抛出 BrokenBarrierException)。实际使用中建议:
- 在 barrier action 中不抛出未捕获异常,否则屏障立即破损
- 若需多次执行同一批线程的分段计算,确保每次开始前 barrier 处于可用状态(可通过 isBroken() 判断)
- 避免在 await() 前后依赖屏障未触发的状态,因为 barrier action 和后续执行存在时序耦合
不复杂但容易忽略:合并逻辑若涉及 IO 或锁竞争,应移出 barrier action,改为仅做轻量级收集,再由主线程或独立任务处理。

















