CountDownLatch 的原理

CountDownLatch 是 Java 并发包(java.util.concurrent)中的一个同步工具类,用于协调多个线程之间的执行顺序,其核心原理是通过一个计数器控制线程的等待与唤醒。

核心原理

  1. 初始化计数器
    创建 CountDownLatch 实例时,需要指定一个初始计数器值(count),该值通常代表需要等待的任务数量或事件数量。
    例如:CountDownLatch latch = new CountDownLatch(3); 表示需要等待 3 个事件完成。

  2. 线程等待(await()
    当线程调用 latch.await() 方法时,会检查计数器的值:

    • 如果计数器 > 0,当前线程会进入阻塞状态,并加入到 CountDownLatch 内部的等待队列中,释放 CPU 资源。
    • 如果计数器 == 0,线程会直接继续执行,不阻塞。
  3. 计数器递减(countDown()
    当某个任务或事件完成时,线程调用 latch.countDown() 方法,将计数器的值减 1
    当计数器的值减到 0 时CountDownLatch 会唤醒所有因调用 await() 而阻塞的线程,让它们继续执行。

  4. 不可重置性
    计数器一旦减到 0,就无法再被重置(与 CyclicBarrier 不同),即 CountDownLatch 只能使用一次。

内部实现细节

CountDownLatch 的底层依赖 AQS(AbstractQueuedSynchronizer,抽象队列同步器) 实现,AQS 是 Java 并发工具的基础框架,用于管理线程的等待队列和状态同步。

  • CountDownLatch 内部定义了一个继承自 AQS 的同步器(Sync),将 AQS 的 state 变量复用为计数器的值。
  • await() 方法对应 AQS 的共享式获取同步状态:当 state > 0 时,线程加入等待队列并阻塞。
  • countDown() 方法对应 AQS 的共享式释放同步状态:每次调用将 state 减 1,当 state == 0 时,唤醒所有等待线程。

典型使用场景

  • 等待多个子任务完成:例如主线程等待所有子线程执行完毕后再汇总结果(如你提供的代码中,等待所有异步计算任务完成)。
  • 协调线程执行顺序:例如让多个线程等待某个 “开始信号”(计数器初始为 1,主线程调用 countDown() 后所有线程同时启动)。

示例流程

// 1. 初始化计数器为 2(需要等待 2 个任务)
CountDownLatch latch = new CountDownLatch(2);

// 线程 1:执行任务1
new Thread(() -> {
    System.out.println("任务1执行中...");
    latch.countDown(); // 计数器减1(变为1)
}).start();

// 线程 2:执行任务2
new Thread(() -> {
    System.out.println("任务2执行中...");
    latch.countDown(); // 计数器减1(变为0,唤醒等待线程)
}).start();

// 主线程:等待两个任务完成
latch.await(); // 计数器为0时,此处不再阻塞
System.out.println("所有任务完成,主线程继续执行");

输出结果:

任务1执行中...
任务2执行中...
所有任务完成,主线程继续执行

总结:CountDownLatch 通过计数器的增减实现线程间的同步,核心是 “等待方” 阻塞至 “计数器归零”,适用于一次性的多线程协作场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值