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。
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时,才会继续执行。
1、什么是CountDownLatch?
答:CountDownLatch是一个同步辅助类,它允许一个或多个线程等待其他线程完成一组操作后再继续执行,它通过一个计数器来实现这个功能,计数器的初始值表示需要等待的操作数量,每完成一个操作,计数器就减1,当计数器的值为0时,表示所有操作都已经完成,此时所有等待的线程都会被唤醒。
2、CountDownLatch是如何解决并发问题的?
答:CountDownLatch通过提供一个等待/通知机制来解决并发问题,当多个线程需要等待其他线程完成一组操作时,它们可以在CountDownLatch对象上调用await()方法来阻塞自己,直到计数器的值为0,这样可以避免忙等和轮询,提高程序的效率和可读性,由于CountDownLatch是基于AbstractQueuedSynchronizer实现的,它利用了底层的FIFO等待队列来管理等待的线程,确保了线程的安全性和可见性。