CountDownLatch原理剖析

简介: CountDownLatch原理剖析

1. 简介


简单描述CountDownLatch的功能,那就是在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待


2. 实现原理


网络异常,图片无法展示
|


CountDownLatch 是通过一个计数器来实现的,当我们在 new 一个 CountDownLatch 对象的时候,需要带入该计数器值,该值就表示了线程的数量。


每当一个线程完成自己的任务后,计数器的值就会减 1 。当计数器的值变为0时,就表示所有的线程均已经完成了任务,然后就可以恢复等待的线程继续执行了。
如上图示例,用给定的计数为3进行初始化 CountDownLatch。由于调用了 countDown方法,所以在当前计数到达0之前,await方法会一直受阻塞;当计数到达0时会唤醒await方法阻塞的线程执行。


3. 源码结构


网络异常,图片无法展示
|


  • J.U.C包中的最核心部分就是AQS的实现,它是JDK并发工具的实现基石,CountDownLatch也不例外,也是基于AQS进行实现
  • await、countDown方法分别调用了AQS的doAcquireShared、doReleaseShared方法以共享锁的形式对AQS的共享变量state进行操作
  • await方法阻塞等待,CountDownLatch 的作用是允许 1 或 N 个线程等待其他线程完成执行
  • countDown方法变更计数,CountDownLatch 的计数器无法被重置


4. 实现剖析


4.1 await方法


网络异常,图片无法展示
|


  • 调用await() 方法,来使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断
  • 该方法内部使用 AQS 的 acquireSharedInterruptibly(int arg) 方法
  • 在内部类 Sync 中重写了 tryAcquireShared(int arg) 方法
  • 通过AQS中的getState() 方法,获取同步状态,其值等于计数器的值
  • 如果计数器值不等于 0,则会调用 doAcquireSharedInterruptibly(int arg) 方法,该方法为一个自旋方法会尝试一直去获取同步状态


4.2 countDown方法


网络异常,图片无法展示
|


  • 调用countDown() 方法,来改变计数器数量
  • 内部调用AQS的releaseShared() 方法
  • Sync重写了tryReleaseShared() 方法
  • 释放锁,也就是操作计数器的过程,这里使用到了CAS(compareAndSetState)进行计数更新,若更新失败则进行自旋重试直到成功为止


4.3 getCount方法


调用AQS的getState方法获取计数


5. 实战用例


模拟主线程await阻塞,等待子线程计数countDown到0唤醒主线程执行


/**

* created by guanjian on 2020/12/28 11:19

*/

public class CountDownLatchTest {


   private static final CountDownLatch cdl = new CountDownLatch(3);


   public static void main(String[] args) throws InterruptedException {

       System.out.println("开始");


       new Thread(() -> {

           try {

               System.out.format("当前计数=%s,需等待 \n", cdl.getCount());

               Thread.sleep(1000);

               cdl.countDown();

               System.out.format("当前计数=%s,需等待 \n", cdl.getCount());

               Thread.sleep(1000);

               cdl.countDown();

               System.out.format("当前计数=%s,需等待 \n", cdl.getCount());

               Thread.sleep(1000);

               cdl.countDown();

           } catch (Exception e) {

               e.printStackTrace();

           }

       }).start();


       cdl.await(6000, TimeUnit.MILLISECONDS);

       print();

       System.out.println("结束");

   }


   private static void print() {

       System.out.println("执行了");

   }

}


【控制台输出】

开始

当前计数=3,需等待

当前计数=2,需等待

当前计数=1,需等待

执行了

结束


6. 总结


  • CountDownLatch的作用实际是提供了一种多线程通信的方式
  • AQS提供了多个线程并发且产生竞态条件时共享变量的安全读写方式,且丰富地提供了共享、排他两种处理竞态线程获取共享资源的方式
  • CountDownLatch利用AQS的state共享变量作为信号量,await方法会在state不等于0时进行阻塞,countDown方法会操作state共享变量改变这个信号量的值从而来影响整个CountDownLatch的运行
  • CountdownLatch是通过共享方式对锁进行操作,通过自旋方式进行阻塞等待,通过CAS对共享变量进行更新保证原子性


7. 参考


http://www.iocoder.cn/JUC/sike/CountDownLatch/

相关文章
CountDownLatch实现原理全面解析
CountDownLatch是一个同步工具类,用来协调多个线程之间的同步(即:用于线程之间的通信而不是互斥)。它允许一个或多个线程进入等待状态,直到其他线程执行完毕后,这些等待的线程才继续执行。
|
7月前
|
设计模式 Java
CountDownLatch和CyclicBarrier源码详解
我现在有个场景:现在我有50个任务,这50个任务在完成之后,才能执行下一个函数,要是你,你怎么设计?可以用JDK给我们提供的线程工具类,CountDownLatch和CyclicBarrier都可以完成这个需求。基于AQS实现,会将构造CountDownLatch的入参传递至statecountDown()就是在利用CAS将state减1,await)实际就是让头节点一直在等待state为0时,释放所有等待的线程。
73 1
|
4月前
|
Java 数据库 开发者
CountDownLatch、CyclicBarrier和Semaphore原理和区别
CountDownLatch、CyclicBarrier和Semaphore
|
4月前
CyclicBarrier原理
文章主要介绍了CyclicBarrier的工作原理和使用场景。CyclicBarrier适用于需要多个线程同步到达某个点后再一起继续执行的情况,它通过ReentrantLock和Condition实现了高效的线程同步机制,适合用于需要循环使用屏障点的场景。
CyclicBarrier原理
|
4月前
|
消息中间件 RocketMQ
CountDownLatch原理
文章讲述了CountDownLatch的工作原理及其用途: 1. CountDownLatch是一个简单的同步工具,用于等待一组操作完成。 2. 它通过AQS框架实现,利用共享锁模式控制线程的等待与唤醒。 3. 适用于多线程环境下,一个线程需要等待多个其他线程完成各自的任务后再继续执行的场景。
|
4月前
|
Java
CountDownLatch、CyclicBarrier 使用区别
CountDownLatch、CyclicBarrier 使用区别
37 1
|
7月前
CountDownLatch 实战
CountDownLatch 实战
58 0
|
7月前
并发编程之CountDownLatch和CyclicBarrier的详细解析(带小案例)
并发编程之CountDownLatch和CyclicBarrier的详细解析(带小案例)
100 0
|
7月前
学习多线程之CountDownLatch使用
学习多线程之CountDownLatch使用
60 0
CountDownLatch和CyclicBarrier的区别
CountDownLatch和CyclicBarrier的区别
41 0