1. 首先看一下CountDownLatch的构造函数
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
然后看一下Sync类,是一个静态内部类,继承了AQS,重写了tryAcquireShared()
与tryReleaseShared()
两个共享的方法
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
Sync(int count) {
setState(count);
}
int getCount() {
return getState();
}
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -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;
}
}
}
构造对象时,传入state初始值
2. 看一下countDown()方法
public void countDown() {
sync.releaseShared(1);
}
countDown时会把state-1,看一下releaseShared()方法的实现
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
tryReleaseShared()
为内部类实现,如果state = state-1设置成功,并且state为0时返回true,为true时调用了doReleaseShared()
方法。介绍完await()方法再介绍此方法
3. 看一下await()方法
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
await方法中获取1个状态,最终调用内部类实现的tryAcquireShared()
方法,此方法只有在state==0时才返回1,否则返回-1(返回-1表示state>0,也就是计数没有用完),调用doAcquireSharedInterruptibly()
方法,看一下此方法
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.SHARED);
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} catch (Throwable t) {
cancelAcquire(node);
throw t;
}
}
addWaiter()
方法表示增加一个新Node节点到等待队列尾部,并返回这个新节点。当执行到tryAcquireShared()
方法时,若state!=0,返回-1,后面会进入parkAndCheckInterrupt()
方法等待
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
4. 下面看一下doReleaseShared()方法
private void doReleaseShared() {
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
!h.compareAndSetWaitStatus(0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
看一下unparkSuccessor()
方法
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
node.compareAndSetWaitStatus(ws, 0);
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node p = tail; p != node && p != null; p = p.prev)
if (p.waitStatus <= 0)
s = p;
}
if (s != null)
LockSupport.unpark(s.thread);
}
unparkSuccessor()
方法会唤醒等待的线程,正好唤醒上面await()
方法park的线程
5. 总结
利用AQS的state表示计数值,每次调用countDown()方法时会减一,当减到0时会唤醒await()方法等待的线程。
实时内容请关注微信公众号,公众号与博客同时更新:程序员星星