latch : 门闩,闭锁的意思。
在aqs的注释里,作者写了一个BooleanLatch,用来做单一门闩的类。
跟CountDownLatch很类似了。只是CountDownlatch是多个控制,而BooleanLatch只有一个控制。
CountDownLatch并不限制线程数,只限制countDown的次数
终于回到了CountdownLatch了。
CountDownLatch就是使用的AQS,也就是ReentrantLock里面使用的aqs。
怎么用的呢?
比如,CountDownLatch初始化的时候,设置的count,就是aqs的state = n。
从aqs的意义上来说,就是有一个线程重入了n次。
然后没调用一次countDown,就把state-1.
直到state = 0了,那么主线程就可以跑了。
countDownLatch只有三个方法:
构造方法
await
countDown
构造方法 中,创建aqs,将state设置为count,假设是2.
countDown方法中,先自旋给state-1.
countDown的构造方法中,连aqs都没有创建,head都没有!!只是设置了一个门闩state = count
所以在countDown的方法中,只是把state-1,而aqs的doReleaseShared的方法中直接就是break
await方法中,先去看一看state是不是为0. 如果是0就直接过去了。
如果不是0,进doAcquireSharedInterruptibly方法。
也就是在head后面加一个shared的节点,等待在head后面。
所以,countDown和await应当是分开的两个线程的操作,或者说如果非要在一个线程中执行的话,await也应该在countDown之后。
为什么呢?因为await会park,而无法等待到countDown。
就好像,有业主A开车要从小区出去,如果这个时候,门卫B走路或者骑自行车去开门,这个时候。
如果门卫先到,业主后到,那么业主不需要等待,直接出门。
如果业主后到,门卫先到,那么业主需要等待门卫来开门,再出去。
如果门卫也是开车,被业主堵住了。
那业主哪怕等到天黑,他也出不去了,因为出现了死锁,门卫在等业主,业主在等门卫。
1. CountDownLatch在什么时候会构造aqs?
CountDownLatch在一开始的构造方法并不会创建一个aqs,而是在await并且等待的时候,加入share节点,发现没有head的时候,才会创建aqs。
2. countDown完之后,主线程就会跑吗?
不一定,跑不跑,等不等,取决于哪个线程在await,和什么时候await。比如像上面那个死锁的情况,那就天荒地老也不会跑
3. 如果有好几个线程都await呢?
那么当countDown到0之后,这好几个线程都unpark,因为他们加的都是share锁,也就是读锁。