并发编程:CountDownLatch

并发编程:CountDownLatch_第1张图片

首先CountDownLatch是JUC(java.util-concurrent)下面的并发编程工具类,JDK1.5才出现的。

CountDownLatch

是一个倒计时工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行。

生活中的场景有:开会场景,咱们要等全部人都到期后才开会,所以来一个人空位总数就减一,直到空位为0时,就开始开会。

直接上demo代码:

/**
* @author lawt
* @date 2018-09-10 9:18
* CountDownLatch使用案例
* 模拟开会场景,当所有人到场后就开始开会
**/
public class CountDownLatchDemo {
/**
    * 参会人员必须要20
    */
   private static final int THREAD_TOTAL_NUM = 20;
/**
    * 计数器
    */
   private static final CountDownLatch COUNT_DOWN_LATCH = new CountDownLatch(THREAD_TOTAL_NUM);

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

for (int i = 0; i < THREAD_TOTAL_NUM; i++) {
int index = i + 1;
new Thread(() -> {
               try {
                   System.out.println("" + index + "个人到场");
                   //这个人到会花的时间
                   Thread.sleep(new Random().nextInt(3000));
               } catch (Exception ex) {
                   ex.printStackTrace();
               }
               //index人员到场
               COUNT_DOWN_LATCH.countDown();

           }).start();
}
//检查是否全部人员都到场
       COUNT_DOWN_LATCH.await();
System.out.println("人员都已经到场,可以开会了");
}
}

运行结果:

并发编程:CountDownLatch_第2张图片

并发编程:CountDownLatch_第3张图片

并发编程:CountDownLatch_第4张图片

如果仅仅是使用,到此就可以了,如果想了解深一点可以继续往下看:

CountDownLatch的几个方法

  • await():如果当前count大于0,当前线程将会wait,直到count等于0或者中断。PS:当count等于0的时候,再去调用await(),线程将不会阻塞,而是立即运行。后面可以通过源码分析得到。

  • await(long timeout, TimeUnit unit):使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。

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

  • getCount() :获得计数的数量


CountDownLatch的构造函数

并发编程:CountDownLatch_第5张图片

然后调用Sync的构造方法,使用AQS的state表示计数count

并发编程:CountDownLatch_第6张图片

再到AQS中的setState()方法

并发编程:CountDownLatch_第7张图片

另外state的定义volatile修饰的,说明具有可见性,就是当一个线程修改CountDownLatch(num)中的num时,其他线程是可见的。

countDown方法 

并发编程:CountDownLatch_第8张图片

如果当前count大于0,则减一,

并发编程:CountDownLatch_第9张图片

并发编程:CountDownLatch_第10张图片


await方法

640?wx_fmt=png

AQS:acquireSharedInterruptibly(int arg) 

并发编程:CountDownLatch_第11张图片

CountDownLatch$Sync:int tryAcquireShared(int acquires)

并发编程:CountDownLatch_第12张图片

这里的state就是最开始new CountDownLatch(int count),count等于state

如果获取共享锁继续调用doAcquireSharedInterruptibly(arg)

并发编程:CountDownLatch_第13张图片

for (;;) {//本质是等待共享锁的释放,死循环。

int r = tryAcquireShared(arg);//就判断尝试获取锁

这里要注意一下r的值就2种情况-1和1:

  • r为-1,latch没有调用countDown(),state是没有变化的导致state一直大于0或者调用了countDown(),但是state不等于0,直接在for循环中等待

  • r为1,证明countDown(),已经减到0,当前线程还在队列中,state已经等于0了.接下来就是唤醒队列中的节点 

当前节点不是头结点,当前线程一直等待,直到获取到共享锁


如果这里多个线程wait之间没有调用countDown(),线程都在等待

如下图:

并发编程:CountDownLatch_第14张图片


释放共享锁,通知后面的节点。AQS中的doReleaseShared方法,这一块主要是AQS中的代码,之前已经讲过了,所以这里不重提了。见

并发编程:CountDownLatch_第15张图片






你可能感兴趣的:(并发编程:CountDownLatch)