本节一起学习CountDownLatch类的源码
1.类变量信息
private final Sync sync;
2.构造函数
public CountDownLatch(int count) { if (count < 0) throw new IllegalArgumentException("count < 0"); this.sync = new Sync(count); }
3.Sync内部类,继承AQS,实现同步
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; } } }
4.常用的方法
public void countDown() {//一个线程处理完成后,锁个数减1 sync.releaseShared(1); }
public void await() throws InterruptedException {//等待所有线程处理完成 sync.acquireSharedInterruptibly(1); }
AQS:
public final boolean releaseShared(int arg) { if (tryReleaseShared(arg)) {//如果所有线程处理完成 doReleaseShared();//唤醒等待队列中的节点 return true; } return false; }
private void doReleaseShared() { for (;;) { Node h = head; if (h != null && h != tail) { int ws = h.waitStatus; if (ws == Node.SIGNAL) { if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) continue; // loop to recheck cases unparkSuccessor(h);//唤醒节点的后继者 } else if (ws == 0 && !compareAndSetWaitStatus(h, 0, Node.PROPAGATE)) continue; // loop on failed CAS } if (h == head) // loop if head changed break; } }
/** * 唤醒节点 * @param node the node */ private void unparkSuccessor(Node node) { int ws = node.waitStatus; if (ws < 0) compareAndSetWaitStatus(node, ws, 0);//设置状态为初始状态 Node s = node.next; if (s == null || s.waitStatus > 0) { s = null; for (Node t = tail; t != null && t != node; t = t.prev) if (t.waitStatus <= 0) s = t; } if (s != null) LockSupport.unpark(s.thread);//唤醒线程 }
public final void acquireSharedInterruptibly(int arg) throws InterruptedException { if (Thread.interrupted())//线程中断 throw new InterruptedException(); if (tryAcquireShared(arg) < 0)//如果线程未处理完 doAcquireSharedInterruptibly(arg); }
/** * Acquires in shared interruptible mode. * @param arg the acquire argument */ private void doAcquireSharedInterruptibly(int arg) throws InterruptedException { final Node node = addWaiter(Node.SHARED);//封装节点,加入等待队列 boolean failed = true; try { for (;;) { final Node p = node.predecessor(); if (p == head) { int r = tryAcquireShared(arg);//查询线程是否都处理完成 if (r >= 0) { setHeadAndPropagate(node, r);//设置head p.next = null; // help GC failed = false; return; } } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())//中断线程 throw new InterruptedException(); } } finally { if (failed) cancelAcquire(node); } }
总结:
CountDownLatch类底层通过AQS控制,首先初始化计数器,countDown时,计数器减1,当计数器等于0时,会唤醒AQS等待队列中的线程。
await方法,如果计数器等于0,则返回true,否则会加入到等待队列中,如果等待队列再次查询计数器还是不等于0,则会中断线程,等待被唤醒。