CountDownLatch
是 Java 并发包 (java.util.concurrent
) 中的一个同步工具类,用于让一个或多个线程等待其他线程完成操作。它通过一个计数器来实现线程的等待和通知机制,适用于主线程等待多个子线程完成任务的场景。
核心概念
- 计数器:
CountDownLatch
内部维护一个计数器,初始化时指定计数器的初始值。- 每当一个线程完成任务时,调用
countDown()
方法,计数器减 1。 - 当计数器减到 0 时,等待的线程会被唤醒。
- 一次性:
CountDownLatch
的计数器只能减少,不能重置。如果需要重复使用,可以考虑使用CyclicBarrier
。
常用方法
CountDownLatch(int count)
:- 构造函数,创建一个
CountDownLatch
,指定计数器的初始值。
- 构造函数,创建一个
await()
:- 使当前线程等待,直到计数器减到 0。
countDown()
:- 将计数器减 1,表示一个线程已完成任务。
getCount()
:- 返回当前计数器的值。
使用场景
- 主线程等待子线程完成任务:
- 例如,主线程需要等待多个子线程完成初始化操作后再继续执行。
- 并行任务同步:
- 多个线程并行执行任务,主线程等待所有任务完成后进行汇总。
- 测试多线程程序:
- 在测试中模拟多个线程同时执行任务的场景。
代码示例
以下是一个简单的 CountDownLatch
示例,模拟主线程等待多个子线程完成任务:
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
// 创建一个 CountDownLatch,计数器初始值为 3
CountDownLatch latch = new CountDownLatch(3);
// 创建 3 个子线程
for (int i = 0; i < 3; i++) {
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + " 开始执行任务");
Thread.sleep(1000); // 模拟任务执行
System.out.println(Thread.currentThread().getName() + " 任务完成");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown(); // 计数器减 1
}
}).start();
}
// 主线程等待所有子线程完成任务
System.out.println("主线程等待子线程完成任务");
latch.await();
System.out.println("所有子线程任务完成,主线程继续执行");
}
}
输出结果:
主线程等待子线程完成任务
Thread-0 开始执行任务
Thread-1 开始执行任务
Thread-2 开始执行任务
Thread-0 任务完成
Thread-1 任务完成
Thread-2 任务完成
所有子线程任务完成,主线程继续执行
注意事项
- 计数器不可重置:
CountDownLatch
的计数器只能减少,不能重置。如果需要重复使用,可以考虑使用CyclicBarrier
。
- 异常处理:
- 如果子线程在执行任务时抛出异常,需要确保
countDown()
方法被调用,否则主线程可能会一直等待。
- 如果子线程在执行任务时抛出异常,需要确保
- 性能影响:
- 如果计数器初始值设置过大,可能会导致主线程长时间等待,影响程序性能。
与 CyclicBarrier
的区别
- 可重用性:
CountDownLatch
是一次性的,计数器减到 0 后不能再使用。CyclicBarrier
是可重用的,屏障被打破后可以重置。
- 使用场景:
CountDownLatch
适用于主线程等待多个子线程完成任务的场景。CyclicBarrier
适用于多个线程互相等待,达到一个共同的屏障点后再继续执行的场景。
总结
CountDownLatch
是 Java 并发编程中用于线程同步的重要工具,适用于主线程等待多个子线程完成任务的场景。通过合理使用 CountDownLatch
,可以简化多线程编程的复杂性,提高代码的可读性和可维护性。
THE END
暂无评论内容