什么是 Java 的 CountDownLatch?

Sherwin.Wei Lv7

什么是 Java 的 CountDownLatch?

回答重点

CountDownLatch 是 JUC 中的一个同步辅助类,它允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。CountDownLatch 通过一个计数器来实现,计数器的初始值由构造方法传入。每当一个线程完成工作后,计数器会递减。当计数器到达零时,所有等待的线程会被唤醒并继续执行。

主要功能

  1. 等待事件完成:通过 await() 方法,线程可以等待其他线程完成某些操作。
  2. 递减计数器:其他线程在完成各自的任务后,通过调用 countDown() 方法将计数器减 1。
  3. 线程同步:当计数器变为 0 时,所有调用了 await() 的线程将被唤醒并继续执行。

扩展知识

内部实现原理

  • CountDownLatch 的内部使用 AbstractQueuedSynchronizer (AQS) 实现。计数器的递减操作本质上是通过 AQS 来实现同步机制的。
  • 当调用 countDown() 时,内部的 state 值减少,并在 await() 中通过检查 state 是否为 0 来决定是否唤醒等待线程。

注意

  • 由于 CountDownLatch 无法重用,它适合用于一次性的任务完成同步。如果需要重复使用,需要使用 CyclicBarrier 或其他机制。

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
// 计数器为 3,表示需要等待 3 个任务完成
CountDownLatch latch = new CountDownLatch(3);

// 启动 3 个线程来执行任务
for (int i = 1; i <= 3; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 执行任务");
latch.countDown(); // 每个线程执行完任务后递减计数器
}).start();
}

System.out.println("等待所有任务完成...");
latch.await(); // 主线程等待所有任务完成
System.out.println("所有任务已完成,继续执行主线程");
}
}

输出示例

1
2
3
4
5
等待所有任务完成...
Thread-1 执行任务
Thread-2 执行任务
Thread-3 执行任务
所有任务已完成,继续执行主线程

使用场景

  • 并行计算结果汇总:可以用于汇聚多个线程的结果,等所有子任务完成后再执行后续逻辑。
  • 任务完成信号:在某些场景下,需要多个任务都完成后才能继续执行后续逻辑,比如在应用启动时,等待所有服务启动后再提供服务。
  • 测试并发场景:在编写并发测试时,利用 CountDownLatch 可以确保多个线程在某一时刻同时开始执行,测试并发场景下的行为。

与 CyclicBarrier 的对比

  • CountDownLatch:一次性使用,计数器减到 0 后,不能再次复用。
  • CyclicBarrier:可以重用,所有线程到达屏障后会自动重置,允许多次使用。
Comments