当前位置:首页 > 行业动态 > 正文

CountDownLatch源码解析之await

CountDownLatch的await方法会阻塞当前线程,直到计数器减到零。

CountDownLatch是一个同步辅助类,在多线程编程中发挥着重要作用,它允许一个或多个线程等待其他线程完成一组操作后再继续执行。

CountDownLatch的工作原理

1、初始化

CountDownLatch通过构造函数接收一个计数器初始值count,这个计数器表示需要等待的其他线程完成的操作数量。

内部维护了一个同步队列(基于AQS实现),用于管理等待的线程。

2、计数器递减

当某个线程完成了它的任务后,会调用countDown()方法,这会导致计数器减1。

如果计数器的值变为0,表示所有线程都已经完成,此时会唤醒所有在await()方法上等待的线程。

3、等待机制

调用await()方法的线程会被阻塞,直到计数器的值为0。

await()方法内部,实际上是调用了sync.acquireSharedInterruptibly(1),其中sync是CountDownLatch的一个内部类,继承自AbstractQueuedSynchronizer。

acquireSharedInterruptibly方法首先检查当前线程是否已经被中断,如果是,则抛出InterruptedException异常。

它调用tryAcquireShared(int acquires)方法来尝试获取锁,如果计数器的值为0,则返回1,表示获取成功;否则返回-1,表示获取失败。

如果获取失败,线程会被加入到同步队列中等待,直到计数器的值为0。

await方法的源码解析

1、方法签名

public void await() throws InterruptedException:这是CountDownLatch类中的一个实例方法,用于使当前线程等待,直到计数器的值为0。

2、方法实现

await()方法内部,直接调用了sync.acquireSharedInterruptibly(1)

这个调用会触发一系列复杂的操作,包括检查线程是否被中断、尝试获取锁、处理等待队列等。

示例代码

以下是一个使用CountDownLatch的简单示例:

public class Main {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(3);
        new Thread(() -> {
            try {
                System.out.println("子线程1正在运行");
                Thread.sleep(1000); // 模拟任务执行时间
                latch.countDown();
                System.out.println("子线程1完成任务");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(() -> {
            try {
                System.out.println("子线程2正在运行");
                Thread.sleep(2000); // 模拟任务执行时间
                latch.countDown();
                System.out.println("子线程2完成任务");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(() -> {
            try {
                System.out.println("子线程3正在运行");
                Thread.sleep(1500); // 模拟任务执行时间
                latch.countDown();
                System.out.println("子线程3完成任务");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        System.out.println("主线程等待所有子线程完成");
        latch.await(); // 主线程等待所有子线程完成任务
        System.out.println("所有子线程已完成,主线程继续执行");
    }
}

在这个示例中,我们创建了一个CountDownLatch对象,其计数器初始值为3,然后启动了三个子线程,每个子线程在完成任务后都会调用latch.countDown()方法,主线程在调用latch.await()方法后会等待,直到所有子线程都调用了countDown()方法,即计数器的值为0时,才会继续执行。

FAQs

1、什么是CountDownLatch?

答:CountDownLatch是一个同步辅助类,它允许一个或多个线程等待其他线程完成一组操作后再继续执行,它通过一个计数器来实现这个功能,计数器的初始值表示需要等待的操作数量,每完成一个操作,计数器就减1,当计数器的值为0时,表示所有操作都已经完成,此时所有等待的线程都会被唤醒。

2、CountDownLatch是如何解决并发问题的?

答:CountDownLatch通过提供一个等待/通知机制来解决并发问题,当多个线程需要等待其他线程完成一组操作时,它们可以在CountDownLatch对象上调用await()方法来阻塞自己,直到计数器的值为0,这样可以避免忙等和轮询,提高程序的效率和可读性,由于CountDownLatch是基于AbstractQueuedSynchronizer实现的,它利用了底层的FIFO等待队列来管理等待的线程,确保了线程的安全性和可见性。