Java CyclicBarrier 详解:原理、使用方式与应用场景

原文来自于:[zha-ge.cn/java/75http...

Java CyclicBarrier 详解:原理、使用方式与应用场景

说起来多线程,真的是一把双刃剑,玩的爽的时候效率飞起,踩坑的时候能让你想砸键盘。那天被产品催着搞个并发汇总批量处理,"必须所有线程都处理完才能出最终结果哈!"老板一句话,我心里mmp冒了三句,然后想到了老朋友------CyclicBarrier。

那些年被读写锁捣鼓晕了

先给没见过 CyclicBarrier 的朋友科普一句,它的意思其实就是"循环栅栏",就像个闸门------得等所有小伙伴都到了门口,门一开大家再齐头并进。所以它适用于那种"大家一起做点事,等大家都干完才能继续"的场合。

一开始你可能想:"我用 CountDownLatch 不就行?"确实,俩有点像。但 CyclicBarrier 能用多轮,Latch 一次性的,完事就没法再用了。

突发奇想用 CyclicBarrier 干票大的

我的场景是这样:假如有三个子线程,必须等它们都到齐,聚在一起后,才能合体出最终报告。伪代码像这样:

java 复制代码
CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("大家一起出发!"));

for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        // 各自干各自的活
        doSomething();
        try {
            barrier.await(); // 等到小伙伴都到了
        } catch (Exception e) {
            // 啊又爆炸了!
        }
        // 继续后续操作
    }).start();
}

哪怕你有 30 个线程也照样安排,只要前面数字一样,线程就小学生排队似的,你来我来大家一起闯关。

踩坑瞬间

别以为 CyclicBarrier 就完美了哈!我第一次用的时候,线程里有个"不小心"抛了个 Exception,结果整个 barrier.await 就等到天荒地老。啥原因?原来只要有一个 thread 异常退出了,其他的就都被冻那了------barrier 一直等不到齐活。

总结几个坑点:

  • 有一个线程异常退出,整个 barrier 卡死,剩下的线程永远等不来 release。
  • 重复利用 CyclicBarrier 时,记住 barrier.reset() 是把大家拉回起跑线,但正在等待的那帮线程会直接收到异常(BrokenBarrierException),得做好异常处理。
  • 提前触发 barrier 任务(那第二个参数 Runnable),如果任务失败也会导致大家全都抛异常。

举个踩坑代码片段,全靠经验教训:

java 复制代码
try {
    barrier.await();  // 这里如果线程提前崩了,剩下的人就直接 BrokenBarrierException了
} catch (BrokenBarrierException | InterruptedException e) {
    // 做好善后,不然你得加班写年终总结......
}

CyclicBarrier 最妙的感觉

用完 CyclicBarrier,我体会到最美的一刻就是三个线程像打卡上班,一起蹲在门口,等班长(barrier任务)发指令,然后啪,一起冲。特别适合:

  • 多个线程数据计算,最后聚合
  • 分段下载,等分块都好了再合成
  • 测试场景下模拟"大部队"同时开火

别的场景你也可以"想歪用一下",比如刷队伍小游戏(拼手速),别愣着,场景绝对取之不尽。

经验启示

又到了填鸡汤瓶的时间------自己亲身试过后,才发现:

  • CyclicBarrier 爱凑数儿,线程数对不上就没得玩
  • 一定要处理异常,尤其是 BrokenBarrierException
  • 它循环可重用,比 CountDownLatch 强在玩多轮赛
  • barrier内部有个"小小黑屋"(generation),重置和异常都会让大家被踢出来,记得写好兜底

最后送你一张我的偷懒手册:

关键点 记忆口诀
对线程数有要求 人没到齐,门不开
适合多轮齐步走 一拨儿走完还能再来一拨
异常要特别留意 讹出一个,全员搁浅

溜了溜了......

写的累,但 CyclicBarrier 用顺了是真香。前提是你真知道自己要的啥,别上线了一堆线程尬等。对了,如果你也踩过啥多线程的坑,评论里一起唠嗑,帮我打打气,下次再写点更野的故事!

相关推荐
杨杨杨大侠2 小时前
打开 JVM 黑匣子——走进 Java 字节码(一)
java·jvm·agent
SimonKing2 小时前
接口调用总失败?试试Spring官方重试框架Spring-Retry
java·后端·程序员
咖啡Beans3 小时前
SpringCloud网关Gateway功能实现
java·spring cloud
杨杨杨大侠3 小时前
Atlas Mapper 案例 01:初级开发者 - 电商订单系统开发
java·开源·github
华仔啊3 小时前
Java 8都出了这么多年,Optional还是没人用?到底卡在哪了?
java
用户093 小时前
Gradle Cache Entries 深度探索
android·java·kotlin
叽哥3 小时前
Kotlin学习第 9 课:Kotlin 实战应用:从案例到项目
android·java·kotlin
阿杆4 小时前
同事嫌参数校验太丑,我直接掏出了更优雅的 SpEL Validator
java·spring boot·后端
Grey Zeng13 小时前
Java SE 25新增特性
java·jdk·jdk新特性·jdk25