基于CountDownLatch讲AQS之共享锁

一、用法

先看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方法。这样就可以把所有的线程唤醒了。

 

你可能感兴趣的:(java多线程)