countdownlatch
一、用法
先看countdownlatch的用处和用法
每个线程如果持有同一个CountDownLatch,当他们都调用countdownLatch的await()方法的时候,他们都会被挂起,只有当countdownLatch的数量减到0的时候,他们才会同时开始执行(这里CycliBarrier也可以做的)。也可以用它来控制线程的同时执行。如果把countDown放在run方法里,也可以做到等哪些执行结束,某个线程再执行。
二、看源码
首先会发现我们常用的几个方法都来自sync这个类。而sync继承AQS。这里原理之前分析过。
我们先来看await方法。它的目的是挂起执行这个方法的线程。
核心就是看tryAcquireShared的值是否小于0,如果小于0就执行do方法。
这个try方法是业务线的。
countDownLatch里面的这个方法
只做了一件事,就是当前状态值是不是为0,不是就返回-1.
结合上面的,就是只要你的countDownLatch里面的值没有减到0,就执行方法。
这里只说核心的(有很多跟排它锁一样的,在之前文章中说过了)
先是以声明一个共享锁的节点,并入队等待队列中。
然后取它的前一个节点,看是不是头节点,如果是,就再次执行do方法,看看countdownLatch里面的值是不是为0了。如果是,就进行setHeadAndPropagate方法 。如果不是,就按之前的套路把这个线程挂起。
这个方法主要做了什么?
1.先是把把自己设置为head节点。
2.核心是进行doReleaseShared方法。这里先暂停,回去看countDownLatch的countDown方法。
它的本质是是调用releaseShared方法。
它先是判断try方法是不是为true.这里这个方法是业务线的。
这个方法就是进行值减一,一开始就是0,说明不能减,那就返回false。如果进行减法后,值为0,那就返回true。然后就会进行doRealseShared方法。所以这里可以猜到do方法里面一定会把之前调用await的线程唤醒。
这个方法就是从head开始,看他的状态如果是signal,就向后检查,找到第一个不是取消状态的,就唤醒它,如果是初始状态,就改成向后传播的状态。
但是这里只是唤醒head下的第一个节点。但是我们知道countDownLatch是唤醒所以使用了await的线程,这个就靠之前的方法了。
这里回到之前那个方法,
head下的第一个节点被唤醒了,执行了try方法,此时countDown的值已经是0了,可以执行这个方法了。先是把自己设置成了新的head,然后因为try的返回值大于0,所以这里有接着执行doReleaseShared方法,然后成功后,又会执行setHeadAndPropagate方法。这样就可以把所有的线程唤醒了。