news 2026/7/5 3:32:48

CountDownLatch 实现精准的并发控制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CountDownLatch 实现精准的并发控制

CountDownLatch 实现精准的并发控制

概述

本文档详细分析并发启动场景(赛跑模式)中两个 CountDownLatch 的作用和阻塞关系。


代码示例

importjava.util.concurrent.CountDownLatch;publicclassRaceStartDemo{publicstaticvoidmain(String[]args)throwsInterruptedException{finalintrunnerCount=10;finalCountDownLatchreadyLatch=newCountDownLatch(runnerCount);// 计数器=10finalCountDownLatchstartLatch=newCountDownLatch(1);// 计数器=1// 启动10个运动员线程for(inti=0;i<runnerCount;i++){finalintid=i;newThread(()->{try{System.out.println("运动员 "+id+" 准备就绪");readyLatch.countDown();// ← 不阻塞,只是计数-1startLatch.await();// ← 阻塞的是运动员线程!System.out.println("运动员 "+id+" 起跑!");}catch(InterruptedExceptione){e.printStackTrace();}}).start();}// 主线程(裁判)readyLatch.await();// ← 阻塞的是主线程!System.out.println("\n所有运动员就位,准备发令!");Thread.sleep(500);startLatch.countDown();// ← 主线程执行,唤醒所有运动员System.out.println("砰!");}}

两个 Latch 对比

Latch谁调用 await()阻塞的是谁谁调用 countDown()初始计数作用
readyLatch主线程主线程各个 Runner 线程10主线程等待所有运动员就位
startLatchRunner 线程Runner 线程主线程1运动员等待发令枪

执行流程图

┌─────────────────────────────────────────────────────────────┐ │ Phase 1: 准备阶段 │ ├─────────────────────────────────────────────────────────────┤ │ Runner-1: readyLatch.countDown() (不阻塞) readyLatch: 10→9 │ │ Runner-2: readyLatch.countDown() (不阻塞) readyLatch: 9→8 │ │ ... │ │ Runner-10: readyLatch.countDown() (不阻塞) readyLatch: 1→0 │ │ │ │ 主线程: readyLatch.await() ←─────── 阻塞主线程! │ │ 等待 readyLatch 从 10 减到 0 │ └─────────────────────────────────────────────────────────────┘ ↓ readyLatch == 0 主线程被唤醒 ┌─────────────────────────────────────────────────────────────┐ │ Phase 2: 起跑阶段 │ ├─────────────────────────────────────────────────────────────┤ │ Runner-1: startLatch.await() ←─────── 阻塞运动员线程! │ │ Runner-2: startLatch.await() ←─────── 阻塞运动员线程! │ │ ... │ │ Runner-10: startLatch.await() ←────── 阻塞运动员线程! │ │ │ │ 主线程: startLatch.countDown() startLatch: 1→0 │ │ (发令枪!) │ └─────────────────────────────────────────────────────────────┘ ↓ startLatch == 0 所有运动员线程被唤醒,开始跑!

形象类比:赛跑场场景

🏁 赛跑场场景 🏃‍♂️ Runner-1 🏃‍♂️ Runner-2 🏃‍♂️ Runner-10 │ │ │ │准备就绪 │准备就绪 │准备就绪 ▼ ▼ ▼ countDown() countDown() countDown() (报到) (报到) (报到) 👨‍💼 裁判(主线程) │ readyLatch.await() │ ⏳ 等待中... (所有人都报到了,readyLatch == 0) │ startLatch.countDown() ←─── 砰!发令枪 ────→ │ 所有 Runner 被唤醒,开始跑!

详细时间线

时间轴 → T0: 主线程启动 10 个 Runner 线程 T1: Runner-1 执行 readyLatch.countDown() (readyLatch: 10→9) T2: Runner-2 执行 readyLatch.countDown() (readyLatch: 9→8) ... T10: Runner-10 执行 readyLatch.countDown() (readyLatch: 1→0) T11: 主线程的 readyLatch.await() 返回!主线程继续执行 T12: 主线程打印 "所有运动员就位,准备发令!" T13: 主线程 sleep 500ms T14: 主线程执行 startLatch.countDown() (startLatch: 1→0) T15: 所有阻塞在 startLatch.await() 的 Runner 线程被唤醒! T16: 所有 Runner 开始跑

关键点总结

❌ 常见误解

错误理解:两个 Latch 阻塞的都是主线程

✅ 正确理解

Latch阻塞的线程谁来唤醒
readyLatch主线程Runner 线程们(通过 countDown)
startLatchRunner 线程们主线程(通过 countDown)

为什么需要两个 Latch?

只用一个 CountDownLatch 无法实现这种精确的同步:

  • 只用 readyLatch:主线程可以等待运动员就位,但无法控制运动员同时起跑
  • 只用 startLatch:运动员可以等待发令枪,但主线程不知道运动员是否都准备好了

双 Latch 设计实现了:

  1. 确保所有运动员都就位后,裁判才发令
  2. 确保所有运动员同时收到发令信号,公平起跑

适用场景

这种双 Latch 模式适用于:

  • ✅ 需要多个线程同时启动的场景
  • ✅ 需要主线程确认所有子线程准备就绪
  • ✅ 需要精确控制并发开始时机
  • ✅ 批量任务并行执行,要求同时开始

与 CyclicBarrier 的对比

特性CountDownLatch(双 Latch)CyclicBarrier
等待方向互为依赖(互相等待)所有线程互相等待
重用性不可重用可循环使用
线程数量主线程 + 子线程所有线程地位平等
典型场景主控并发并行计算分阶段

总结

核心要点

  1. readyLatch 阻塞主线程:主线程等待所有子线程准备就位
  2. startLatch 阻塞子线程:子线程等待主线程发令
  3. 互相等待:实现精确的并发控制
  4. 一次性使用:CountDownLatch 计数归零后无法重置

阻塞关系速记

┌─────────────┐ ┌─────────────┐ │ 主线程 │────────▶│ readyLatch │ 阻塞主线程 │ (裁判) │ └─────────────┘ └─────────────┘ ▲ │ │ Runner 线程们 │ countDown() │ ┌─────────────┐ ┌─────────────┐ │ Runner们 │◀────────│ startLatch │ 阻塞 Runner 们 │ (运动员) │ └─────────────┘ └─────────────┘ ▲ │ │ 主线程 │ countDown()(发令枪)

总结:readyLatch 让裁判等待运动员,startLatch 让运动员等待裁判。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/5 3:31:58

商用烤盘定制厂家正规机构

做过烘焙供应链的都懂&#xff0c;商用烤盘是直接影响生产效率和产品品质的核心工具&#xff0c;尤其是有定制需求的食品加工厂、中央厨房&#xff0c;找对正规的烘焙器具定制厂家&#xff0c;能避开后续不少麻烦&#xff1a;比如定制尺寸和产线不匹配卡炉、用两三个月就变形翘…

作者头像 李华
网站建设 2026/7/5 3:31:22

从 OC 平滑迁移 Swift 完整方案

前言&#xff1a;重构不是推倒重来&#xff0c;是技术债务的有序偿还 对于大多数运行了5年以上的iOS大型项目来说&#xff0c;几十万行Objective-C代码沉淀了无数业务逻辑、边缘场景和经过亿级用户验证的稳定逻辑。直接全量重写为Swift的项目几乎无一例外都陷入了工期无限延期…

作者头像 李华
网站建设 2026/7/5 3:29:58

VIbe Coding时期,推送项目惹众宾欢也

在进行 vibe coding 时&#xff0c;容易在项目推送环节翻车&#xff0c;比如大家常调侃的将 API 密钥推送到仓库的情况。本文就为大家讲清楚 DeepSeek API 如何安全推送。摘要&#xff1a;本文详细介绍了在 vibe coding 过程中如何安全地将项目推送到 GitHub&#xff0c;避免泄…

作者头像 李华
网站建设 2026/7/5 3:29:01

小红书数据采集终极指南:Python xhs库完整实战教程

小红书数据采集终极指南&#xff1a;Python xhs库完整实战教程 【免费下载链接】xhs 基于小红书 Web 端进行的请求封装。https://reajason.github.io/xhs/ 项目地址: https://gitcode.com/gh_mirrors/xh/xhs 在当今社交媒体数据分析领域&#xff0c;小红书作为中国领先的…

作者头像 李华
网站建设 2026/7/5 3:27:25

DeepSeek API 零基础接入指南:从 VS Code 插件到命令行调用

&#x1f680; 30款热门AI模型一站整合&#xff0c;DeepSeek/GLM/Qwen 随心用&#xff0c;限时 5 折。 &#x1f449; 点击领海量免费额度 1. 先搞清楚 DeepSeek 到底是什么&#xff0c;以及“一键安装”能解决什么问题 如果你看到“DeepSeek”和“一键安装”这两个词&…

作者头像 李华
网站建设 2026/7/5 3:27:17

python神经网络编程入门(一)—— 分类器

写这篇专栏&#xff0c;一来是为了帮自己把一些基础知识梳理得更扎实&#xff0c;二来也是因为现在网上“调包侠”太多了——我不反对用现成的库快速解决业务问题&#xff0c;毕竟实用主义没毛病&#xff0c;但很多内容打着“AI”的旗号&#xff0c;却只教人“from sklearn imp…

作者头像 李华