云计算百科
云计算领域专业知识百科平台

Java - CountDownLatch、CyclicBarrier、Semaphore 三大JUC同步器实战对比

Java – CountDownLatch、CyclicBarrier、Semaphore 三大 JUC 同步器实战对比

目录

  • 引言

  • 一、JUC 同步器核心基础概念

    • 2.1 同步器的本质与作用

    • 2.2 核心底层支撑:AQS 同步队列

    • 2.3 三大同步器的核心差异概览

  • 二、深度解析 CountDownLatch:减法计数器型同步器
    • 2.1 核心设计思想与工作机制

    • 2.2 底层源码实现逻辑(基于 AQS 共享模式)

    • 2.3 企业级实战代码:并行任务结果汇总

    • 2.4 典型业务适用场景

    • 2.5 使用注意事项与避坑点

  • 三、深度解析 CyclicBarrier:可循环屏障型同步器
    • 3.1 核心设计思想与工作机制

    • 3.2 底层源码实现逻辑(ReentrantLock+Condition)

    • 3.3 企业级实战代码:分片数据并行处理与合并

    • 3.4 典型业务适用场景

    • 3.5 使用注意事项与避坑点

  • 四、深度解析 Semaphore:许可证池型同步器
    • 4.1 核心设计思想与工作机制

    • 4.2 底层源码实现逻辑(基于 AQS 共享模式)

    • 4.3 企业级实战代码:高并发接口限流模拟

    • 4.4 典型业务适用场景

    • 4.5 使用注意事项与避坑点

  • 五、三大同步器核心业务场景横向对比
    • 5.1 场景一:多任务并行执行 & 结果汇总

    • 5.2 场景二:并发流量控制与资源隔离

    • 5.3 场景三:多线程分段执行 & 循环同步

    • 5.4 功能特性对比表

  • 六、性能实测对比(基于 JMH)
    • 6.1 测试环境与设计方案

    • 6.2 吞吐量测试结果

    • 6.3 延迟测试结果

    • 6.4 性能差异深度分析

  • 七、生产级调优建议与最佳实践
    • 7.1 CountDownLatch 调优建议

    • 7.2 CyclicBarrier 调优建议

    • 7.3 Semaphore 调优建议

    • 7.4 通用并发调优原则

  • 八、选型决策指南

  • 九、总结


  • 引言

    在 Java 多线程编程中,线程同步是保证数据安全、控制执行顺序、避免资源竞争的核心手段。java.util.concurrent(简称 JUC)包下提供了三大核心同步工具类:CountDownLatch、CyclicBarrier、Semaphore,它们基于 AQS(AbstractQueuedSynchronizer)同步框架实现,屏蔽了底层同步状态管理、线程排队、线程阻塞与唤醒的复杂逻辑,开发者可以直接使用它们实现高精度的线程协同。

    但在实际项目中,很多开发者对三者的设计初衷、适用场景、底层逻辑认知模糊,经常出现滥用场景、忽略并发边界、没有处理异常边缘 Cases 等问题,导致生产环境出现线程永久阻塞、并发量过高、数据不一致等严重故障。

    本文将从底层原理、实战代码、场景适配、性能对比、调优指南五个维度,对三大同步器进行全方位深度剖析。通过真实企业级业务场景代码、可量化的性能测试数据、生产级的避坑建议,帮助所有阶段的开发者(初级理解基础用法、中级掌握场景选型、高级优化底层并发逻辑)彻底掌握这三大同步器,在实际项目中做出正确的技术选型,写出稳定、高性能的并发代码。


    一、JUC 同步器核心基础概念

    2.1 同步器的本质与作用

    同步器是一种线程协同机制,它可以控制多个线程的执行顺序、线程之间的等待 / 唤醒逻辑、以及多线程对共享资源的并发访问权限。

    在并发编程中,线程的执行时序是由操作系统调度器随机决定的,无法通过常规代码控制执行先后顺序。而同步器的核心价值,就是提供了人为可控的调度能力:

    • 让某个线程等待其他线程执行完成后再继续;

    • 让多个线程在同一时间点统一开始执行;

    • 限制同一时间内访问某个资源的最大线程数;

    • 实现线程之间的结果传递与执行进度同步。

    2.2 核心底层支撑:AQS 同步框架

    三大同步器的底层,几乎都依赖AbstractQueuedSynchronizer(简称 AQS)同步框架。AQS 是 JUC 包的核心底层基础组件,它封装了同步状态管理、线程排队、线程阻塞与唤醒、共享 / 独占模式区分等基础同步能力,极大降低了上层同步器的实现复杂度。

    AQS 的核心设计要点:

  • 同步状态:用一个volatile int state变量表示同步状态,state 的具体含义由上层同步器自定义。

  • 两种同步模式:

    • 独占模式:同一时间只能有一个线程获取同步状态(如 ReentrantLock);

    • 共享模式:同一时间可以有多个线程获取同步状态(三大同步器均基于共享模式实现)。

  • CLH 队列:一个基于双向链表实现的线程等待队列,所有获取锁失败的线程都会进入该队列阻塞,等待前驱线程释放锁后被唤醒。
  • 注:

    CyclicBarrier

    是唯一的例外,它没有直接使用 AQS,而是基于

    ReentrantLock

    (底层依赖 AQS)和

    Condition

    条件等待机制实现,本质上还是间接依赖了 AQS 的能力。

    2.3 三大同步器的核心差异概览

    特性维度
    CountDownLatch
    CyclicBarrier
    Semaphore
    核心逻辑 减法计数器,计数归零时唤醒等待线程 加法计数器,计数达到设定值时唤醒所有线程 许可证池,线程必须持有许可证才能访问资源
    可重复性 一次性使用,计数归零后无法重置 可循环使用,计数归零后自动重置 可动态调整许可证数量,重复使用
    等待主体 一个或多个线程,等待其他线程完成任务 多个线程互相等待,到达同一执行屏障 多个线程,等待可用的许可证资源
    典型用途 并行任务结果汇总、主线程等待子任务执行完成 多线程分段执行、并行计算结果合并、模拟并发场景 接口限流、资源隔离、控制第三方服务并发访问量
    底层同步模式 AQS 共享模式 ReentrantLock+Condition(间接依赖 AQS) AQS 共享模式

    二、深度解析 CountDownLatch:减法计数器型同步器

    2.1 核心设计思想与工作机制

    CountDownLatch是一种基于减法计数器的一次性同步工具。它的核心逻辑是:初始化时设定一个正整数作为计数器的初始值,一个或多个线程可以通过await()方法进入阻塞状态,等待计数器归零;其他线程在完成任务后,需要调用countDown()方法将计数器减一;当计数器的值递减到零时,所有因调用await()方法而阻塞的线程都会被自动唤醒,继续执行后续逻辑。

    核心工作流程:

  • 初始化CountDownLatch,设置计数器初始值(通常需要等待的子线程任务数量);

  • 主线程调用await()方法,进入阻塞状态,等待计数器归零;

  • 每个子线程任务执行完成后,调用countDown()方法,将计数器减 1;

  • 当所有子线程都执行完成,计数器递减至 0 时,主线程被唤醒,继续执行后续汇总逻辑。

  • 2.2 底层源码实现逻辑(基于 AQS 共享模式)

    CountDownLatch的底层实现,是通过一个内部类Sync继承了 AQS 的共享模式能力。它对 AQS 的复用逻辑非常简洁:

  • 同步状态含义:AQS 中的state变量,在这里被直接用作计数器的当前值。

  • 获取共享锁逻辑:当线程调用await()方法时,会尝试获取共享锁,只有当state(计数器值)为 0 时,获取锁的操作才会成功;否则,线程会被封装成节点,放入 AQS 的 CLH 等待队列中阻塞。

  • 释放共享锁逻辑:当线程调用countDown()方法时,会将state原子性减 1;如果减 1 后state的值变为 0,说明所有子任务都执行完成,此时会遍历 CLH 等待队列,唤醒所有等待的主线程。

  • 核心源码片段(JDK8):

    // CountDownLatch内部类Sync,继承AQS

    private static final class Sync extends AbstractQueuedSynchronizer {

      Sync(int count) {

      setState(count); // 初始化state为计数器初始值

      }

      // 省略其他方法

    }

    // 构造方法,初始化计数器

    public CountDownLatch(int count) {

    &#x20; if (count < 0) throw new IllegalArgumentException(\”count < 0\”);

    &#x20; this.sync = new Sync(count);

    }

    // 等待计数器归零

    public void await() throws InterruptedException {

    &#x20; sync.acquireShared(1); // 调用AQS的共享锁获取方法

    }

    // 计数器减1

    public void countDown() {

    &#x20; sync.releaseShared(1); // 调用AQS的共享锁释放方法

    }

    2.3 企业级实战代码:并行任务结果汇总

    业务场景说明

    在电商平台的商品详情页接口中,需要并行调用多个底层服务获取核心数据:商品基本信息、商品库存信息、商品价格信息、商品营销活动信息。这些接口之间没有依赖关系,串行调用耗时会叠加,通过CountDownLatch可以实现并行调用,主线程等待所有接口返回结果后,再组装成完整的商品详情数据返回,有效缩短接口响应时间。

    完整代码示例

    import java.util.concurrent.CountDownLatch;

    import java.util.concurrent.ExecutorService;

    import java.util.concurrent.Executors;

    import java.util.concurrent.TimeUnit;

    // 并行任务结果汇总示例

    public class CountDownLatchBusinessDemo {

    &#x20; // 模拟需要并行调用的4个业务接口

    &#x20; private static final int TASK\\_COUNT = 4;

    &#x20; // 创建固定线程池,管理并行任务线程

    &#x20; private static final ExecutorServic

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Java - CountDownLatch、CyclicBarrier、Semaphore 三大JUC同步器实战对比
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!