cyclicbarrier 的回调函数在所有线程到达屏障后、任一线程被释放前由最后一个到达的线程同步执行一次,用于安全汇总、校验或轻量通知,不支持耗时操作。

Java 中 CyclicBarrier 的回调函数(即构造时传入的 Runnable)会在所有线程都到达屏障点后、**任一线程被释放前**执行,适合做汇总、清理或触发后续动作等“屏障级”任务。
回调函数的触发时机很关键
它不是每个线程到达时都调用,而是等最后一个线程调用 await() 进入等待后,由该线程(或内部选中的一个线程)**同步执行**回调,再唤醒其他线程。这意味着:
- 回调在屏障“解锁前”执行,此时所有线程仍处于阻塞状态,共享数据是线程安全的(无竞争)
- 回调中抛出异常会传播给所有正在 await 的线程(包装为
BrokenBarrierException) - 回调只执行一次,哪怕屏障被重置后再次触发
典型用途:结果聚合与状态检查
比如多个线程各自计算一部分数据,最后在回调里合并结果:
// 示例:4 个线程并行计算数组分段和,用 CyclicBarrier 汇总
List<integer> partialSums = Collections.synchronizedList(new ArrayList());
CyclicBarrier barrier = new CyclicBarrier(4, () -> {
int total = partialSums.stream().mapToInt(Integer::intValue).sum();
System.out.println("全部完成,总和:" + total);
// 可在此清空列表、写入数据库、发通知等
});
</integer>
注意:partialSums 要用线程安全容器,因为多个线程会在 await 前写入;而回调内读取是安全的——此时写入已全部完成。
回调中能做的事有边界
它不适合耗时操作(会拖慢所有线程释放),也不建议启动新线程或调用阻塞方法。合理做法包括:
- 读取/合并各线程预存的结果(如上面的 sum)
- 校验整体状态(例如是否所有任务都成功,如有失败可设全局标志)
- 更新共享控制变量(如设置
isCompleted = true) - 记录日志或发送轻量通知(非网络 I/O)
与 CountDownLatch 的回调区别要分清
CountDownLatch 没有内置回调,常靠外部轮询或配合 ExecutorService.invokeAll() 实现类似效果;而 CyclicBarrier 的回调是原生支持、严格按屏障语义执行的。如果需要“每轮都回调”,用 CyclicBarrier 更直接;如果只是“等全部结束再干一件事”,且不需重用,CountDownLatch 加单独线程也能实现,但逻辑更松散。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











