深入理解 JUC:CountDownLatch
CountDownLatch 是一个同步辅助工具,用于阻塞当前一个或多个线程以等待其它线程中的操作完成。在构造 CountDownLatch 对象时,我们需要指定一个非负的 count 值,一般情况下,调用 CountDownLatch#await
方法的线程需要阻塞等待该 count 值变为 0 时才能够继续往下执行。具体示例可以参考 理清 CountDownLatch 与 CyclicBarrier 的区别。
CountDownLatch 实现内幕
CountDownLatch 在实现上同样依赖于 AQS 组件,在 CountDownLatch 的内部定义了一个 Sync 内部类,该类继承自 AbstractQueuedSynchronizer,并复用 AQS 的 state 字段以记录 count 值的变化。CountDownLatch 的核心方法均委托 Sync 进行处理,实现如下:
1 | public class CountDownLatch { |
下面我们主要分析一下 CountDownLatch#await
和 CountDownLatch#countDown
方法的实现。
首先来看一下 CountDownLatch#await
方法,该方法用于阻塞当前线程,直到 count 值变为 0,或者被其它线程中断。具体实现上,CountDownLatch 直接将请求委托给 AQS 的 AbstractQueuedSynchronizer#acquireSharedInterruptibly
方法进行处理,所以我们下面主要来看一下 CountDownLatch 针对模板方法 AbstractQueuedSynchronizer#tryAcquireShared
的实现,如下:
1 | protected int tryAcquireShared(int acquires) { |
实现上非常简单,获取并判定状态值是否为 0,如果是则说明当前线程获取资源成功,能够继续往下执行,否则说明当前线程获取资源失败,需要被添加到同步队列阻塞等待。CountDownLatch 还为 CountDownLatch#await
方法定义了超时版本 CountDownLatch#await(long, TimeUnit)
。
继续来看一下 CountDownLatch#countDown
方法,该方法用于将 count 值减 1,如果发现 count 值变为 0,则唤醒阻塞等待的线程。具体实现上,CountDownLatch 同样直接将请求委托给 AQS 的 AbstractQueuedSynchronizer#releaseShared
方法进行处理,所以我们下面主要来看一下 CountDownLatch 针对模板方法 AbstractQueuedSynchronizer#tryReleaseShared
的实现,如下:
1 | protected boolean tryReleaseShared(int releases) { |
具体实现如代码注释,比较简单。需要注意的一点就是上面步骤中的判 0 操作,刚开始看的时候可能觉得有点多余,但是这一步的主要作用在于保证 state 值不会变为负值。当前 count 值变为 0 时,上述方法会返回 true,接下去 AQS 会执行唤醒之前因为 count 值不为 0 而被打入同步队列的线程。
总结
CountDownLatch 的实现机制到此就分析完了,因为依赖于 AQS,所以 CountDownLatch 在实现上变得十分简单,但是功能却很强大。下一篇我们将要分析与 CountDownLatch 极为容易混淆的 CyclicBarrier 组件,从实现层面去理清二者的区别。