当前位置: 首页 > news >正文

孤舟笔记 并发篇三十二 CountDownLatch和CyclicBarrier有什么区别?别再搞混了

文章目录

    • 一、先说结论:核心区别一览
    • 二、CountDownLatch:一个人等大家
    • 三、CyclicBarrier:大家互等,到齐了一起走
    • 四、核心区别:能不能互换?
    • 五、异常处理的差异
    • CountDownLatch vs CyclicBarrier 全景
    • 回答技巧与点评
        • 标准回答
        • 加分回答
        • 面试官点评

个人网站

面试常问一道题:“CountDownLatch 和 CyclicBarrier 有什么区别?“很多人背了"一个是倒计数,一个是循环屏障”,但再追问"什么时候用哪个”、“能不能互换”、“CyclicBarrier 的屏障动作是什么”,就支支吾吾了。

今天咱们把这两个同步工具彻底对比清楚,以后再也不搞混。

一、先说结论:核心区别一览

维度CountDownLatchCyclicBarrier
语义等待 N 个事件完成等待 N 个线程到齐
使用者1 个线程等 N 个N 个线程互相等
计数方式countDown() 减 1,await() 等待await() 到齐后自动归零
是否可重用❌ 一次性,不可重置✅ 自动重置,可循环使用
异常影响某个线程异常不影响其他某个线程异常会破坏屏障
回调支持 barrierAction

一句话记住:CountDownLatch 是"等人干完活",CyclicBarrier 是"等人到齐了一起走"。

二、CountDownLatch:一个人等大家

场景:主线程需要等待所有子任务完成后才继续执行。

CountDownLatchlatch=newCountDownLatch(3);// 计数 3// 三个子线程executor.submit(()->{loadData();latch.countDown();// 计数 -1 👈});executor.submit(()->{loadConfig();latch.countDown();// 计数 -1 👈});executor.submit(()->{initCache();latch.countDown();// 计数 -1 👈});latch.await();// 主线程等计数归零 👈System.out.println("所有初始化完成,开始业务");

生活类比:就像聚餐——你是组织者(主线程),等三拨人都到了才开席。每拨人到了给你发个消息(countDown),你一直等着(await),直到三拨人都到齐。

关键特点:

  1. 等待者和被等待者不是同一拨人——主线程等子线程
  2. 子线程只管 countDown,不需要 await
  3. 一次性——用完就不能再用了

三、CyclicBarrier:大家互等,到齐了一起走

场景:多个线程需要互相等待,全部到齐后一起继续。

CyclicBarrierbarrier=newCyclicBarrier(3,()->{System.out.println("所有选手就位,比赛开始!");// barrierAction 👈});// 三个选手for(inti=0;i<3;i++){newThread(()->{System.out.println(Thread.currentThread().getName()+" 准备好了");barrier.await();// 等其他选手 👈System.out.println(Thread.currentThread().getName()+" 起跑!");}).start();}

生活类比:就像赛跑——所有选手到达起跑线后,裁判鸣枪(barrierAction),大家一起跑。跑完一圈,重新集合,再来一圈。

关键特点:

  1. 等待者就是参与者——大家互相等
  2. barrierAction——到齐后自动执行的回调
  3. 可循环——到齐后自动重置,下一轮继续用

四、核心区别:能不能互换?

场景一:只能用 CountDownLatch

// 主线程等 10 个 HTTP 请求完成// 请求方不需要等别人,只管 countDownCountDownLatchlatch=newCountDownLatch(10);for(inti=0;i<10;i++){executor.submit(()->{httpGet(url);latch.countDown();// 请求方不管别人 👈});}latch.await();// 主线程等

为什么不能用 CyclicBarrier?HTTP 请求方是"干完就走",不需要等别人——而 CyclicBarrier 要求所有参与者都 await。

场景二:只能用 CyclicBarrier

// 多轮计算:每轮所有线程算完才能进入下一轮CyclicBarrierbarrier=newCyclicBarrier(N);for(intround=0;round<10;round++){for(inti=0;i<N;i++){executor.submit(()->{compute();barrier.await();// 每轮都要同步 👈});}}

为什么不能用 CountDownLatch?需要循环使用,CountDownLatch 是一次性的。

场景三:两者都可以

// 3 个线程全部完成后执行汇总// CountDownLatch 版本CountDownLatchlatch=newCountDownLatch(3);// 3 个线程 countDown + 1 个线程 await// CyclicBarrier 版本CyclicBarrierbarrier=newCyclicBarrier(3,()->summary());// 3 个线程 await,barrierAction 做汇总

五、异常处理的差异

异常场景CountDownLatchCyclicBarrier
某个线程异常countDown 少调一次,await 可能永远阻塞屏障被破坏,抛出 BrokenBarrierException
超时await(timeout) 超时返回 falseawait(timeout) 超时抛 TimeoutException
重置不支持reset() 重新开始

CyclicBarrier 的屏障一旦被破坏(某个线程离开 await),所有等待线程都会收到 BrokenBarrierException。

try{barrier.await();}catch(BrokenBarrierExceptione){// 有人退出了,大家散了吧 👈}catch(InterruptedExceptione){// 被中断了}

CountDownLatch vs CyclicBarrier 全景

CountDownLatch vs CyclicBarrier 全景 核心区别 ├── 等待模型 ── 1等N vs N互等 ├── 可重用性 ── 一次性 vs 可循环 ├── 回调 ── 无 vs barrierAction └── 异常 ── 阻塞风险 vs 屏障破坏 CountDownLatch 适用 ├── 主线程等待子任务完成 ├── 一次性场景(启动、关闭) └── 被等待者不需要互相感知 CyclicBarrier 适用 ├── 多线程分阶段计算 ├── 需要循环同步 └── 需要在同步点执行汇总动作 口诀:CountDown 一人等大家,用完即弃不可复, CyclicBarrier 互等齐,循环使用带回调, 异常处理各不同,选错工具会死锁。

回答技巧与点评

标准回答

CountDownLatch 和 CyclicBarrier 都是同步工具,核心区别有三:第一,等待模型不同——CountDownLatch 是"一个线程等待 N 个事件完成",CyclicBarrier 是"N 个线程互相等待到齐";第二,可重用性不同——CountDownLatch 是一次性的,CyclicBarrier 自动重置可循环使用;第三,CyclicBarrier 支持 barrierAction,到齐后自动执行回调。选择时,等待者和参与者不是同一拨人用 CountDownLatch,多线程互相等待且需要循环同步用 CyclicBarrier。

加分回答
  1. 设计模式:CountDownLatch 是"门闩模式"——门关着等所有闩打开;CyclicBarrier 是"栅栏模式"——所有人到齐后一起翻过栅栏。两者都是 AQS 的变体实现,但 CountDownLatch 基于共享模式(AQS 的 state),CyclicBarrier 基于锁+ Condition(ReentrantLock + Condition)
  2. Phaser 的优势:Java 7 引入了 Phaser,可以看作 CyclicBarrier 的增强版——支持动态注册/注销参与者、多阶段同步、分层。当参与者数量不确定或需要多阶段同步时,Phaser 比 CyclicBarrier 更灵活
  3. CountDownLatch 的计数问题:如果某个线程异常退出没有 countDown,await 会永远阻塞。解决方案:用 await(timeout) 代替 await,或者用 ExecutorService + invokeAll 来保证所有任务完成
面试官点评

这道题考的是你对并发同步工具的理解和选型能力。能说出"1等N vs N互等、一次性 vs 可循环"是基本要求,能给出具体场景说明什么时候用哪个,才算及格。如果你能提到 Phaser、AQS 底层实现差异、异常处理策略,面试官会认为你对并发工具的理解不只在 API 层面,而是深入到了设计层面。

原文阅读


内容有帮助?点赞、收藏、关注三连!评论区等你 💪

http://www.jsqmd.com/news/766189/

相关文章:

  • 上海生物实验室如何选恒温摇床?2026年避坑实测指南 - 速递信息
  • 用户如何挑选国内正规恒温摇床销售厂家?2026年实测方案 - 速递信息
  • 英雄联盟玩家必备的5大效率神器:LeagueAkari本地化工具箱完全指南
  • iv8:一键秒杀瑞数6、__zp_stoken__、abogus、h5st
  • 告别U盘!用Windows Server 2022+ADK+MDT打造企业内网无人值守装机系统
  • [t.9.5] Scrum Meeting 5
  • 科研绘图救星:5分钟用Mathematica画出能发论文的3D图与动态图(Plot3D/ListAnimate详解)
  • YOLOv8【第十四章:医疗影像与生物医学篇·第15节】医学 AI 竞赛实战——Kaggle/MICCAI 比赛中的 YOLO 提分技巧!
  • 2026年上海恒温摇床厂商口碑深度研究,为采购者提供可靠参考 - 速递信息
  • 上海用户如何挑选靠谱的二氧化碳培养箱生产厂家?2026年实测方案 - 速递信息
  • 告别软件轮询!用TC27x的PWM硬件触发ADC,实现精准电流采样(附Davinci配置全流程)
  • 医疗影像数据跨院共享总出事?(MCP 2026新增“DICOM元数据级加密”强制条款深度拆解):基于国密SM4的轻量级边缘加解密实践
  • 上海实验室如何筛选厌氧培养箱供应商?2026实测避坑指南 - 速递信息
  • Python爬虫老手踩坑记:当Django遇到XXL-JOB,这些注册、回调、线程池的坑我帮你填平了
  • 上海实验室如何选择正规二氧化碳培养箱?2026实测选购指南 - 速递信息
  • 回溯——括号生成
  • 深度探索DIY Layout Creator:开源电路设计工具的设计哲学与创作实践
  • 无人机/机器人工程师必看:四元数姿态控制中,误差四元数到底该怎么算?
  • 终极ESP32开发指南:从零到物联网项目的完整解决方案
  • 抖音无水印批量下载器:免费获取高清视频、图集与音乐的终极指南
  • 保姆级教程:手把手教你用PMCSR寄存器配置PCIE设备的D-State(附状态迁移流程图)
  • 初创团队在虚拟服务器上通过Taotoken低成本使用多模型能力
  • 5分钟完成FF14国际服汉化:开源中文补丁完全指南
  • MCP 2026医疗数据防护落地指南:5步完成等保2.0+GB/T 39725双标适配,附卫健委备案自查清单
  • 用户如何挑选国内靠谱的二氧化碳培养箱企业?2026年实测方案 - 速递信息
  • Windows 安全中心不等于杀毒软件 ≠ 反间谍程序 ≠ 防火墙
  • 告别if-else混乱:用行为树重构你的ROS2机器人决策逻辑(以Nav2恢复机制为例)
  • 为Claude Code配置Taotoken作为自定义模型供应商的详细指南
  • 太香了!CSS选择器复合玩法+常用属性一网打尽
  • WarcraftHelper:让魔兽争霸3在现代电脑重获新生的终极兼容性修复方案