多线程(27)CountDownLatch

182 阅读3分钟

CountDownLatch是Java并发包java.util.concurrent中的一个同步辅助类,它允许一个或多个线程等待直到在其他线程中执行的一组操作完成。CountDownLatch的工作原理是基于一个计数器,我们在创建CountDownLatch实例时指定计数器的初始值。每当一个指定的操作执行完成时,计数器的值就减一。当计数器的值达到零时,等待在CountDownLatch上的线程就会被唤醒,继续执行。

CountDownLatch的用法

CountDownLatch主要用于两种场景:

  1. 确保某个处理在其他线程运行完毕后再执行:可以在准备执行的线程中调用CountDownLatch.await()方法等待其他线程完成各自的任务。其他线程在完成各自的任务后调用CountDownLatch.countDown()方法。这样,可以保证await()方法阻塞的线程会在其他线程的任务全部完成后继续执行。

  2. 同时开始执行一组操作:所有执行线程都调用await()方法在CountDownLatch上等待,主线程完成一些前置设置后调用countDown()方法,这时所有等待的线程同时开始执行。

CountDownLatch的关键方法

  • CountDownLatch(int count):构造方法,count指定了计数器的初始值。

  • void await() throws InterruptedException:使当前线程等待直到锁存器计数到达零,除非线程被中断。

  • boolean await(long timeout, TimeUnit unit) throws InterruptedException:让当前线程等待直到锁存器计数到达零,除非线程被中断,或者指定的等待时间过去。

  • void countDown():递减锁存器的计数,如果计数到达零,则释放所有等待的线程。

CountDownLatch的示例

考虑一个场景,我们需要加载一些配置数据,启动一些服务等初始化操作完成后,应用才能对外提供服务。我们可以使用CountDownLatch来达成这个需求:

import java.util.concurrent.CountDownLatch;

public class MainApplication {
    public static void main(String[] args) throws InterruptedException {
        // 初始化计数器为3
        CountDownLatch latch = new CountDownLatch(3);

        // 创建并启动3个线程
        new Thread(new Service("Service-1", 1000, latch)).start();
        new Thread(new Service("Service-2", 1000, latch)).start();
        new Thread(new Service("Service-3", 1000, latch)).start();

        // 主线程等待其他线程完成
        latch.await();
        System.out.println("All services are up, Application is starting now");
    }
}

class Service implements Runnable {
    private final String name;
    private final int timeToStart;
    private final CountDownLatch latch;

    public Service(String name, int timeToStart, CountDownLatch latch) {
        this.name = name;
        this.timeToStart = timeToStart;
        this.latch = latch;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(timeToStart);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println(name + " is Up");
        latch.countDown(); // 减少锁存器的计数
    }
}

在这个例子中,我们创建了一个CountDownLatch,其计数器的初始值为3,表示需要等待3个服务全部启动。每个Service线程模拟服务启动过程,并在启动后调用countDown()方法。主线程通过调用await()方法等待所有服务的启动。当所有服务线程调用countDown()方法使计数器减至0时,主线程被唤醒,继续执行。

小结

CountDownLatch是一个非常实用的并发工具类,它通过一个计数器提供了一种简单的线程同步机制。这使得它在如启动应用程序、等待服务初始化、完成一组并发任务等场景下非常有用。