CountDownLatch

CountDownLatch是一个多线程计数器,可以使得一个或多个线程进入等待状态直到计数器的计数为0时,线程再进入执行状态

主要的方法

  • CountDownLatch#CountDownLatch(int)
  • CountDownLatch#countdown()
  • CountDownLatch#await()
  • CountDownLatch#await(int, TimeUnit)
  • CountDownLatch#getCount()

构造方法CountDownLatch#CountDownLatch(int)

public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
    this.sync = new Sync(count);
}

初始化计数器的值,该值不能小于0

CountDownLatch#countdown()

计数减一

public void countDown() {
    // 调用sync类的releaseShared方法
    sync.releaseShared(1);
}

public final boolean releaseShared(int arg) {
    if (tryReleaseShared(arg)) {
        // 如果tryReleaseShared执行的结果为真,则往下执行返回true,否则返回false
        doReleaseShared();
        return true;
    }
    return false;
}

protected boolean tryReleaseShared(int releases) {
    // Decrement count; signal when transition to zero
    for (;;) {
        // state,就是计数,这里获取到计数
        int c = getState();
        // 如果计数已经为0了,则返回false
        if (c == 0)
            return false;
        // 否则nextc = 计数 - 1
        int nextc = c-1;
        // 使用cas设置nextc,成功后返回nextc == 0 ? true : false
        // 为0表示计数countdownLatch已经计数完毕
        if (compareAndSetState(c, nextc))
            return nextc == 0;
    }
}

// 当tryRelaseShard返回true时,执行该方法
private void doReleaseShared() {
    /*
     * Ensure that a release propagates, even if there are other
     * in-progress acquires/releases.  This proceeds in the usual
     * way of trying to unparkSuccessor of head if it needs
     * signal. But if it does not, status is set to PROPAGATE to
     * ensure that upon release, propagation continues.
     * Additionally, we must loop in case a new node is added
     * while we are doing this. Also, unlike other uses of
     * unparkSuccessor, we need to know if CAS to reset status
     * fails, if so rechecking.
     */
    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;
    }
}

CountDownLatch#await()

使得当前线程进入等待状态直到计数为0

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)
        // 如果tryAcquireShard方法返回值小于0,则线程进入等待状态
        // 否则方法直接返回
        doAcquireSharedInterruptibly(arg);
}

protected int tryAcquireShared(int acquires) {
    return (getState() == 0) ? 1 : -1;
}

CountDownLatch#await(int, TimeUnit)

await()方法的带超时版本,为了防止await()无法返回的情况出现

CountDownLatch#getCount()

获取计数

总结

CountDownLatch使用步骤

  1. 在主线程中给定线程计数器CountDownLatch,指定计数
  2. 开启子线程,每当子线程执行完成后调用线程计数器的countdown方法,计数-1
  3. 当计数归0,主线程继续执行