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

CountDownLatch、CyclicBarrier、Semaphore 的区别?

三者都是 JDK 并发包 java.util.concurrent 中用于线程协作的工具类,但设计目标和行为模式有本质区别。

工具类核心模型/比喻关键特性主要用途
CountDownLatch 一次性门闩/倒计时器 1. 一次性:计数器归零后无法重置。
2. 被动等待:一个或多个线程等待其他一组线程完成任务。
主线程等待多个前置服务初始化完成; 模拟并发测试的起跑线。
CyclicBarrier 可循环使用的栅栏 1. 可循环使用:计数器归零后会自动重置,可重复使用。
2. 主动协同:一组线程相互等待,全部到达屏障点后,可执行一个预定义任务,然后一起继续执行。
分阶段任务,如多线程数据计算,需合并每阶段结果; 多线程分批处理任务。
Semaphore 信号量/资源访问许可 1. 控制并发访问数: 基于许可(permits)的模型。
2. 可增减许可: 支持释放许可增加资源数。
3. 常用于资源池或流量控制。
数据库连接池限流; 限流场景(如最多 N 个线程同时访问某 API)。

简单来说:CountDownLatch 是 “我等你”(一等多),CyclicBarrier 是 “我们到齐了一起走”(多等多,可循环),Semaphore 是 “只有 N 个名额,先到先得”(控制流量)。

深度解析

原理/机制

  • CountDownLatch: 内部维护一个计数器 count。初始化时设定一个正整数。线程调用 countDown() 方法会将计数器减 1。调用 await() 的线程会被阻塞,直到计数器变为 0。
  • CyclicBarrier: 内部维护一个计数器 parties 和一个 Runnable 屏障动作(可选)。每个线程调用 await() 表示它已到达屏障,此时计数器减 1。当计数器为 0 时,所有线程被释放,屏障动作(如果存在)会由一个最后到达屏障的线程执行,然后计数器重置为 parties,可开始下一轮循环。
  • Semaphore: 内部维护一组许可(permits)。线程调用 acquire() 尝试获取一个许可,如果无可用许可则阻塞;调用 release() 释放一个许可。可以创建公平或非公平的信号量。

重要底层共性: 它们都依赖于强大的 AQS 框架 来实现底层的线程排队、阻塞与唤醒机制。

代码示例

import java.util.concurrent.*;// 1. CountDownLatch 示例:主线程等待3个前置任务完成
public class CountDownLatchDemo {public static void main(String[] args) throws InterruptedException {CountDownLatch latch = new CountDownLatch(3);ExecutorService executor = Executors.newFixedThreadPool(3);for (int i = 1; i <= 3; i++) {final int taskId = i;executor.submit(() -> {try {// 模拟任务执行耗时Thread.sleep((long) (Math.random() * 1000));System.out.println("Task " + taskId + " completed.");} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {latch.countDown(); // 任务完成,计数器减1}});}System.out.println("Main thread waiting for all tasks...");latch.await(); // 主线程在此阻塞,直到计数器为0System.out.println("All tasks completed. Main thread proceeds.");executor.shutdown();}
}// 2. CyclicBarrier 示例:4个运动员(线程)在起跑线(屏障)集合,然后同时开跑
public class CyclicBarrierDemo {public static void main(String[] args) {int runnerCount = 4;// 屏障动作:当所有运动员都准备好后,由最后一个调用 await() 的线程执行CyclicBarrier barrier = new CyclicBarrier(runnerCount,() -> System.out.println("All runners ready! Go!"));ExecutorService executor = Executors.newFixedThreadPool(runnerCount);for (int i = 1; i <= runnerCount; i++) {final int runnerId = i;executor.submit(() -> {try {System.out.println("Runner " + runnerId + " is preparing...");Thread.sleep((long) (Math.random() * 1000));System.out.println("Runner " + runnerId + " is ready.");barrier.await(); // 运动员到达起跑线等待// 所有运动员都到达后,同时开始跑步System.out.println("Runner " + runnerId + " starts running!");} catch (Exception e) {e.printStackTrace();}});}executor.shutdown();}
}

最佳实践与常见误区

  • CountDownLatch:
    • 最佳实践: 确保 countDown() 在 finally 块中调用,以防任务异常导致计数器无法归零,进而造成主线程永久等待。
  • CyclicBarrier:
    • 常见误区: 如果线程池的核心线程数小于屏障数(parties),且没有足够的空闲线程来处理被释放的线程,可能会导致死锁。例如,一个 parties=5 的 CyclicBarrier 与一个只有 4 个线程的线程池一起使用,就会出现这种问题。
    • 重要特性: 它的 reset() 方法可以强制重置屏障,但会唤醒所有等待的线程并抛出 BrokenBarrierException。屏障在破损(如线程被中断)后,需要重置或新建才能继续使用。
  • Semaphore:
    • 最佳实践: 同样,acquire() 的调用应谨慎,或使用 tryAcquire() 带超时的方法,避免永久阻塞。release() 也建议放在 finally 块中。
    • 公平性: 初始化时可指定是否为公平模式。在竞争激烈且要求严格 FIFO 的场景下,公平模式可以避免线程饥饿。
http://www.jsqmd.com/news/601536/

相关文章:

  • 网站seo优化服务收费标准是如何制定的
  • ESP32 LoRaWAN深度睡眠状态持久化方案
  • 暗黑破坏神2存档编辑:从复杂二进制到可视化操作的蜕变之路
  • SEO外推如何实现长期持续的效果
  • 3个技巧解决窗口尺寸控制难题:WindowResizer开源工具全解析
  • 本科论文初稿怎么写?实测四款写论文的AI工具教程,从开题报告到答辩讲稿全覆盖 - 掌桥科研-AI论文写作
  • AssetStudio深度解析:Unity资源逆向工程的实战技巧与高级应用
  • 原生PDF与扫描件PDF的区别:3秒自测法+提取策略
  • 助你省钱!瑞祥卡线上回收的隐藏福利揭秘 - 团团收购物卡回收
  • AI辅助开发:让快马AI教你如何优化调用openmaic网页版的代码与提示词
  • 云容笔谈多场景落地:出版社AI辅助古籍插画复原与风格化再创作
  • 告别盲目选型:最新跨网文件安全交换系统排名与选购避坑指南 - 飞驰云联
  • 3步构建抖音内容自动化采集流水线
  • LTSC-Add-MicrosoftStore解决方案:Windows 11 24H2 LTSC应用商店高效部署指南
  • 从选题到答辩:毕业之家如何帮你搞定毕业论文?
  • 5分钟掌握阿里云盘Refresh Token扫码获取终极实战指南
  • 股票实时行情-外汇行情-期货行情-全球股市行情-港股行情查询-美股行情-股票价格查询API接口介绍 - Jumdata
  • 终极跨平台游戏串流方案:Sunshine让你在任何设备畅玩PC大作
  • 深度学习模型nli-distilroberta-base解析:从Matlab视角看Transformer
  • 如何用Spek音频频谱分析器轻松掌握音频质量检测:新手入门终极指南
  • G-Helper:华硕笔记本硬件控制的轻量级替代方案与开源工具深度评测
  • 隐私优先方案:OpenClaw+本地Gemma-3-12b-it处理敏感财务数据
  • PROJECT MOGFACE代码理解:辅助阅读与解析复杂Python源码项目
  • 如何高效解决黑苹果无线网卡驱动与蓝牙配置难题?
  • d2s-editor:暗黑破坏神2存档高效管理工具
  • Go的runtime-pprof:生成性能剖析数据文件
  • Omni-Vision Sanctuary生成超分辨率图像:效果对比与参数调优
  • 通义千问1.5-1.8B-Chat-GPTQ-Int4 WebUI与操作系统交互:模拟命令行助手
  • PvZ Toolkit:突破游戏限制的植物大战僵尸创新修改方案
  • OpenStack与Kubernetes协同实战:从虚拟机创建到容器化应用部署的完整流程