countdownlatch是基于AQS的实现,在学习之前必须先懂AQS共享锁的原理。
内部类
countdownlatch里维护了一个内部类Sync继承了AQS,这和reentrantlock系列类似,可以看出AQS的使用一般都是重写两组方法tryAcquire/tryrelease
以及tryAcquireShared/tryreleaseshared
这两组方法选一组实现就可以了
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
Sync(int count) {
setState(count);
}
int getCount() {
return getState();
}
// 只有在state减为零是才能竞争锁成功
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
//对于线程的countdown方法,实际上就是释放共享锁的过程
//cas自旋减1
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;
}
}
}
从上面可以知道,实际上CountDownLatch就是使用的共享锁,将CountDownLatch调用者线程阻塞在队列中(AQS),在构造器时将state置为传进来的count数目,在各个线程执行了足够数量的countdown后就可以唤醒阻塞的线程了。
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
await
//可以看出CountDownLatch是支持超时功能的,调用的是aqs的tryAcquireSharedNanos方法
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
这个方法在state不为0时(内部类的重写),调用了会阻塞住当前线程。
countdown
countdown这个方法就是释放锁,共享线程就会减一,当为0时,才会去调用唤醒方法
public void countDown() {
sync.releaseShared(1);
}
只要阅读过aqs的源码,countdownlatch变得so easy