CountDownLatch
CountDownLatch一般称为“倒计数器”,比如有个任务A,需要等其他几个任务执行完之后才可以执行;或者有这么一个业务:在解析Excel时,需要将Excel中的所有数据解析并校验完主线程才可以继续接下来的任务,这时候就可以使用这个类
基本结构
这个类的功能也是在AQS的基础上实现的,但它与之前说过的几个锁稍微有点不同:像ReentrantLock在加锁的时候state自增1,释放锁的时state自减1,当state为0说明释放锁成功或者说是没有现成占有锁;
但在CountDownlatch中tryAcquireShared方法虽然名字是获取锁,但实现逻辑是:如果state为0说明获取锁成功,否则获取锁失败进入同步队列,该方法用在await()方法中
tryReleaseShared方法方法名虽然是释放锁,但却仅仅是在对state尝试自减操作,它的内部是一个循环操作,每一次的调用tryReleaseShared都会首先判断state是否为0,如果是,那么返回false表示“释放锁失败”,如果不是那么尝试CAS的将state自减1,CAS成功之后会判断此时的值是否为0,如果不是那么表示“释放锁失败”,返回false,否则表示“释放锁成功”,返回true,这里的操作可以永远保证只有一个线程能够因为“释放锁成功”而返回true。tryReleaseShared方法在countDown()方法中被调用。
await
当调用await方法时,如state不为0,那么就会将该线程加入到同步队列中
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
调用的是AQS的acquireSharedInterruptibly方法,在这个方法中调用的是子类Sync的tryAcquireShared方法
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
- 判断state值是否为0,如果为0返回1,说明获取了锁线程继续执行;如果不为0,返回-1,将当前线程放入到同步队列中。等待后续线程的唤醒操作
countDown
当调用countDown方法时会进入循环,state减一
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
- 进入无限循环,获取state值,如果为0直接返回false,表示释放锁失败
- 大于0使用得到的state值减一得到nextc
- 使用CAS的方式将state的值改为nextc,如果失败进入下次循环继续设置,如果成功返回nextc==0
- 如果nextc为0说明state值全部减完,锁成功释放,通知调用await方法被阻塞的线程。如果不为0说明还有线程还没执行完毕,需要等待
以上就是Countdownlatch的基本方法,代码比较简单,主要还是依靠AQS实现的

浙公网安备 33010602011771号