返回

一文读懂CountDownLatch:Java程序员的并发神器

后端

什么是 CountDownLatch?

想像一下你正在主持一场竞赛,共有 10 位参赛者。你需要等待所有参赛者都完成比赛,才能宣布获胜者。而 CountDownLatch 正如其名,是一个倒计时计数器,可以让你在所有线程或任务完成之前暂停主线程。

CountDownLatch 的工作原理

创建 CountDownLatch 对象时,你需要指定等待的线程或任务数。每个线程或任务完成时,调用 countDown() 方法递减计数器。当计数器减为 0 时,等待的线程将被唤醒。

CountDownLatch 的使用

使用 CountDownLatch 非常简单,只需以下步骤:

  1. 创建一个 CountDownLatch 对象,指定等待的任务或线程数。
  2. 在每个任务或线程中,完成任务或线程后调用 countDown() 方法。
  3. 在主线程中,调用 await() 方法等待所有任务或线程完成。

CountDownLatch 的核心方法

CountDownLatch 有两个核心方法:

  • countDown() 方法: 递减计数器。当计数器减为 0 时,等待的线程将被唤醒。
  • await() 方法: 阻塞线程,直到计数器减为 0。如果计数器已减为 0,await() 方法将立即返回。

CountDownLatch 的应用场景

CountDownLatch 可用于多种同步场景,例如:

  • 等待所有线程完成任务,再执行下一步。
  • 等待某个条件满足,再执行。
  • 控制线程之间的协作。

CountDownLatch 源码分析

CountDownLatch 的源码位于 java.util.concurrent.CountDownLatch 类中。CountDownLatch 类包含一个计数器和一个等待队列。当计数器减为 0 时,等待队列中的所有线程都会被唤醒。

总结

CountDownLatch 是一个非常有用的并发工具,可以用来实现各种同步机制。CountDownLatch 的使用非常简单,只需要几个简单的步骤。CountDownLatch 的源码也很简单,它包含一个计数器和一个等待队列。

常见问题解答

  1. 什么时候使用 CountDownLatch?

    当需要等待一组线程完成任务时,可以使用 CountDownLatch。

  2. CountDownLatch 与 CyclicBarrier 有什么区别?

    CountDownLatch 只使用一次,而 CyclicBarrier 可以重复使用。

  3. CountDownLatch 与 Semaphore 有什么区别?

    CountDownLatch 用于等待一组线程完成任务,而 Semaphore 用于控制同时可以访问资源的线程数。

  4. CountDownLatch 的性能如何?

    CountDownLatch 的性能开销很低,因为它是一个轻量级工具。

  5. CountDownLatch 有哪些替代方案?

    使用 join() 方法等待线程完成,或者使用 FutureExecutorService 来管理线程。

代码示例

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CountDownLatchExample {
    public static void main(String[] args) {
        int threadCount = 10;
        CountDownLatch latch = new CountDownLatch(threadCount);
        ExecutorService executor = Executors.newFixedThreadPool(threadCount);

        // 创建并执行任务
        for (int i = 0; i < threadCount; i++) {
            executor.submit(() -> {
                // 模拟任务
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                // 递减计数器
                latch.countDown();
            });
        }

        // 等待所有任务完成
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 所有任务完成,继续执行
        System.out.println("所有任务已完成");
    }
}