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

Java CountDownLatch闭锁完全指南:从概念到源码

Java CountDownLatch闭锁完全指南:从概念到源码

    • 一、🔴 CountDownLatch概述:什么是闭锁?
      • 1.1 🟠 官方定义
      • 1.2 🟡 核心特性
    • 二、🔵 流程图:CountDownLatch核心工作流程
    • 三、🟣 CountDownLatch核心方法详解
      • 3.1 🟤 构造方法
      • 3.2 🟠 await() —— 等待计数器归零
      • 3.3 🟡 countDown() —— 计数器减1
      • 3.4 🟣 其他常用方法
    • 四、🟠 流程图:CountDownLatch的两种经典用法
      • 4.1 🟤 用法一:启动信号(一次触发,多线程同时启动)
      • 4.2 🟠 用法二:完成信号(等待所有任务完成)
      • 4.3 🟡 CountDownLatch vs Thread.join()
    • 五、🟤 底层原理:AQS共享模式
      • 5.1 🔵 核心架构
      • 5.2 🟠 await() 的底层流程
      • 5.3 🟣 countDown() 的底层流程
    • 六、🟢 避坑指南
      • 6.1 🔴 常见陷阱
      • 6.2 🟢 最佳实践清单

🌺The Begin🌺点点关注,收藏不迷路🌺

⬇ ⬇ 底部 ⬇ ⬇

📌本文导读:本文将系统讲解Java中CountDownLatch(闭锁)的核心概念、工作原理和使用方法,从"倒计时门闩"的生动比喻到AQS的底层实现,并通过大量实战示例帮助你掌握这个经典的并发同步工具。全文包含五大核心章节3个彩色流程图9个代码示例。预计阅读时间25分钟


一、🔴 CountDownLatch概述:什么是闭锁?

1.1 🟠 官方定义

根据Oracle官方文档的定义,CountDownLatch是一个同步辅助工具,它允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。

形象比喻CountDownLatch就像一道倒计时门闩(Latch)。门闩上有一个计数器,初始值为N。每当一个线程完成了自己的任务,就拨动一次门闩(计数器减1)。当计数器归零时,门闩"啪"的一声打开,所有被挡在门外的等待线程一拥而入。

1.2 🟡 核心特性

特性说明
计数器不可重置一旦计数器归零,就永久保持开放状态,无法重置
一次性使用这是一个"one-shot"现象——计数不能被重置
等待灵活调用countDown()的线程不需要等待计数器归零就可以继续执行
底层基于AQS使用AQS的共享模式实现

📌与CyclicBarrier的核心区别CountDownLatch是"一次性门闩",CyclicBarrier是"循环栅栏"。前者计数器只减不增,后者可重用。


二、🔵 流程图:CountDownLatch核心工作流程

📋 创建CountDownLatch
计数器 = N

🟢 线程A调用 await
计数器>0, 进入阻塞

🟠 线程1完成任务
调用 countDown

🟡 计数器减1
当前值 = N-1

计数器 == 0?

⏳ 等待线程继续阻塞

🔴 门闩打开

🟣 唤醒所有
等待中的线程

🔵 所有等待线程
继续执行

🟠 线程2完成任务
调用 countDown


三、🟣 CountDownLatch核心方法详解

3.1 🟤 构造方法

// 🔴 初始化计数器为3,表示需要等待3个操作完成CountDownLatchlatch=newCountDownLatch(3);

参数说明count表示需要等待的操作数量。若count小于0,构造方法会抛出IllegalArgumentException

3.2 🟠 await() —— 等待计数器归零

作用:使当前线程阻塞,直到计数器归零。如果计数器已经为零,则立即返回,不会阻塞。

// 🟢 主线程等待try{latch.await();// 阻塞,直到计数器归零}catch(InterruptedExceptione){Thread.currentThread().interrupt();}

带超时的版本

// 🟡 最多等待5秒,超时则继续执行if(latch.await(5,TimeUnit.SECONDS)){System.out.println("所有任务已完成");}else{System.out.println("等待超时,部分任务未完成");}

3.3 🟡 countDown() —— 计数器减1

作用:将计数器减1。当计数器减到0时,释放所有等待线程。

// 🔵 每个子线程完成任务后调用latch.countDown();

⚠️重要特性:调用countDown()的线程不阻塞,会立即继续执行。一个线程可以在不同阶段多次调用countDown()

3.4 🟣 其他常用方法

方法说明
getCount()返回当前计数器的值
await(long timeout, TimeUnit unit)带超时的等待
countDown()减少计数器

四、🟠 流程图:CountDownLatch的两种经典用法

🔵 用法2: 主线程等待工作线程完成

主线程: 创建 latch=N

启动N个工作线程

每个线程完成任务后
调用 countDown

所有N个任务
都完成?

主线程: await返回
继续执行

🟢 用法1: 工作线程等待启动信号

主线程: 创建 latch=1

工作线程调用 await
全部阻塞

主线程完成准备工作

主线程: latch.countDown

所有工作线程同时启动

4.1 🟤 用法一:启动信号(一次触发,多线程同时启动)

根据Oracle官方文档中的示例,CountDownLatch初始化为1时可以作为一个**“启动门闩”**:所有工作线程调用await()等待,直到主线程调用countDown()打开门闩。

// 🔴 场景:所有运动员等待发令枪响publicclassStartSignalDemo{publicstaticvoidmain(String[]args)throwsInterruptedException{intN=5;CountDownLatchstartSignal=newCountDownLatch(1);// 发令枪// 🟢 创建N个运动员(工作线程)for(inti=0;i<N;i++){newThread(()->{System.out.println(Thread.currentThread().getName()+" 已就位,等待发令...");try{startSignal.await();// 等待发令枪响System.out.println(Thread.currentThread().getName()+" 🏃 起跑!");}catch(InterruptedExceptione){Thread.currentThread().interrupt();}},"运动员-"+(i+1)).start();}Thread.sleep(3000);// 模拟准备时间System.out.println("🔴 预备... 砰!");startSignal.countDown();// 发令枪响,所有线程同时启动}}

4.2 🟠 用法二:完成信号(等待所有任务完成)

根据Oracle官方文档的示例,CountDownLatch初始化为N可以用于等待N个任务全部完成

// 🟡 场景:主线程等待所有玩家加载完成publicclassCompleteSignalDemo{publicstaticvoidmain(String[]args)throwsInterruptedException{intplayerCount=10;CountDownLatchdoneSignal=newCountDownLatch(playerCount);// 需要等待10个玩家// 🔵 创建10个玩家线程for(inti=0;i<playerCount;i++){newThread(()->{// 模拟加载过程intprogress=0;while(progress<100){progress+=newRandom().nextInt(20);if(progress>100)progress=100;System.out.println(Thread.currentThread().getName()+" 加载: "+progress+"%");try{Thread.sleep(100);}catch(InterruptedExceptione){}}System.out.println("✅ "+Thread.currentThread().getName()+" 加载完成!");doneSignal.countDown();// 🟣 计数器减1},"玩家-"+(i+1)).start();}// 🔴 主线程等待所有玩家加载完成doneSignal.await();System.out.println("🎮 所有玩家已加载完成,游戏开始!");}}

4.3 🟡 CountDownLatch vs Thread.join()

根据源码分析,CountDownLatch相比Thread.join()有两个重要优势:

对比维度Thread.join()CountDownLatch
等待条件等待线程终止等待计数器归零
灵活性必须持有线程引用countDown()可在任何地方调用
线程池支持无法用于线程池✅ 完美配合线程池使用
// 🔵 配合线程池使用ExecutorServiceexecutor=Executors.newFixedThreadPool(3);CountDownLatchlatch=newCountDownLatch(3);for(inti=0;i<3;i++){executor.submit(()->{// 执行任务latch.countDown();// 无需持有线程引用});}latch.await();// 主线程阻塞executor.shutdown();

五、🟤 底层原理:AQS共享模式

5.1 🔵 核心架构

CountDownLatch内部通过一个继承自AbstractQueuedSynchronizer(AQS)的内部类Sync来实现同步控制。所有对计数器的操作都转交给Sync实例处理。

CountDownLatch

内部类 Sync
继承 AQS

state 字段
存储计数器值

tryAcquireShared
检查 state==0

tryReleaseShared
CAS减1

5.2 🟠 await() 的底层流程

当调用await()时:

  1. 转交给Sync处理
  2. 检查state(计数器)是否等于0
  3. 如果state == 0直接返回(门已开)
  4. 如果state > 0,当前线程进入AQS同步队列阻塞等待

5.3 🟣 countDown() 的底层流程

当调用countDown()时:

  1. 尝试通过CASstate减1
  2. 如果减1后state == 0,调用releaseShared()释放所有等待线程
  3. AQS共享模式下,releaseShared()级联唤醒同步队列中的所有阻塞线程

📌内存可见性保证:根据官方文档,在计数归零之前,一个线程中调用countDown()之前的操作,happen-before另一个线程从await()成功返回之后的操作。


六、🟢 避坑指南

6.1 🔴 常见陷阱

序号陷阱正确做法
计数器与任务数不匹配确保countDown()调用次数等于初始计数器
未处理InterruptedException捕获后恢复中断状态或向上抛出
误以为可以重置计数器CountDownLatch不可重置,如需重用用CyclicBarrier
finally中忘记countDown()即使在异常情况下也要确保计数器减少

6.2 🟢 最佳实践清单

序号实践建议说明
countDown()放在finally确保异常时计数器也能归零
使用await(timeout)防止永久阻塞避免线程无限等待
初始计数器与任务数量保持一致否则死锁或过早触发
需要重置时使用CyclicBarrierCountDownLatch是一次性工具


🌺The End🌺点点关注,收藏不迷路🌺

⬆ ⬆ 顶部 ⬆ ⬆
http://www.jsqmd.com/news/1030897/

相关文章:

  • 2026福州闲置香奈儿LV变现攻略,新手零基础出包必看! - 奢品小当家
  • 2026年无锡代理记账与财税服务全攻略:正规机构选择、避坑指南与一站式解决方案 - 优质企业观察收录
  • 郑州装修哪家好?拒绝隐形增项!盘点郑州山泰装饰全包价格与终身水电质保硬核工艺 - 商业先知
  • 生产级AI代理的8个核心架构模式
  • 2026西昌本地靠谱的地板砖维修、防水补漏公司推荐:紧急渗漏随叫随到,提供免费上门勘察服务、本地直营不转包 - 信息热点
  • 上海迪士尼33VIP预约怎么订?京橙国际旅行社一对一管家式预定攻略 - 热点观察
  • 别低价出手闲置钻石!2026常州添价收30年老牌钻石回收,彩钻裸钻估价更顶 - 薛定谔的梨花猫
  • 权威发布:2026 浪琴全国官方售后网点核验结果出炉 60 + 正规服务地址详细公布 - 浪琴中国服务中心
  • 千万不能错过!2026年最靠谱的淘宝代运营企业大揭秘 - GrowthUME
  • 2026企业知识库选型指南:ONES、zyplayer-doc、PingCode、Confluence等主流方案怎么选
  • 2026微信投票系统年度评测:五款热门工具谁最强? - 微信投票制作
  • EDTA螯合剂:从分子原理到工业应用的全面解析
  • 2026新疆废铜废铁回收公司 实测测评 - LYL仔仔
  • 北京劳力士、雅克德罗保养预约攻略!正规腕表服务渠道查询指南 - 亨得利官方售后
  • 安徽宣城市中职中专毕业可直接包就业的学校哪个好?2026年秋季入学 - 小途xt
  • 2026年乌鲁木齐代理记账与工商注册一站式服务深度选型指南 - 企业名录优选推荐
  • 2026 浦东北美黑胡桃全屋定制工厂 小户型高收纳设计 - 优质企业观察收录
  • 公众号低创作和账号检测异常怎么解决?2026年最新恢复方法+contentany检测
  • 2026不锈钢粉末冶金结构件加工厂家:铜基粉末冶金厂家+铁基粉末冶金厂家+粉末冶金齿轮厂家盘点 - 栗子测评
  • 2026年郑州泳池温泉水处理设备厂家推荐:专业选型指南与成本控制秘诀 - 企业名录优选推荐
  • ZigBee ZCL属性报告机制与自定义端点开发实战解析
  • 一名高复班主任心里话:我见证无数乳源瑶乡学子,在这里完成高考逆袭 - 泓动
  • 赋能企业数字化转型:Dromara SkyEye开源项目核心架构深度解析与全链路协同办公平台部署实战指南
  • 亚马逊云科技生成式AI场景化落地实践指南
  • 经典MC68HC908GP32评估板与MON08调试接口深度解析
  • 2026昆明江诗丹顿回收避坑|内行才懂的变现真相 - 薛定谔的梨花猫
  • 2026年 亨得利官方售后服务体系核验报告:最新全国60余家新址及售后热线优化升级 - 亨得利腕表服务中心
  • i.MX GPU工具链实战:纹理压缩、内存监控与API追踪优化指南
  • 南雄学子复读不用愁!半小时直达!始兴风度高复,助力雄州少年再战 2026 高考 - 泓动
  • 视频画质革命:5个理由选择Video2X实现AI视频放大