24 CountdownLatch

CountdownLatch源码阅读:

其实有了AQS的基础后,CountdownLatch的源码阅读就变得非常简单了,其就是对AQS共享模式的一个应用;

  1. state被设置为构造函数传递的数值;

  2. 每一次countdown都会将state减1;当state等于0的时候,将唤醒队列中的线程;

await方法:

public void await() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
}

//这个方法是AQS的
public final void acquireSharedInterruptibly(int arg)
        throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    if (tryAcquireShared(arg) < 0)
        doAcquireSharedInterruptibly(arg);
}

//tryAcquireShared 由CountdownLatch的Sync类实现: 
protected int tryAcquireShared(int acquires) {
    return (getState() == 0) ? 1 : -1;
}
  1. 调用AQS的acquireSharedInterruptibly方法,该方法首先调用tryAcquireShared方法,如果返回小于0的数字就调用doAcquireSharedInterruptibly方法;

  2. tryAcquireShared 之间判断state是否为0,为0返回1,否则返回-1;

  3. doAcquireSharedInterruptibly方法将再次尝试tryAcquireShared,不成功线程将进入队列休眠;

  4. 结合2、3点再看1:

    1. 首先如果state == 0,那么tryAcquireShared返回1,await返回;线程不会阻塞;
    2. 如果state != 0,那么tryAcquireShared 返回-1,然后调用doAcquireSharedInterruptibly方法,线程进入休眠状态;
  5. 其实线程是否等待,取决于state 是否为0; 那么countDown肯定就是对state的操作了;不难猜测,countDown 一定是对state进行--操作;

countDown方法:

public void countDown() {
    sync.releaseShared(1);
}
//releaseShared是AQS方法
public final boolean releaseShared(int arg) {
    if (tryReleaseShared(arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}
//tryReleaseShared是CountdownLatch的Sync类实现的
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;
    }
}
  1. releaseShared调用tryReleaseShared,如果返回true,那么调用doReleaseShared();

  2. tryReleaseShared 只有在state == 0时 才会返回true;

  3. doReleaseShared();即是AQS中唤醒后续线程的逻辑;

  4. 结合2、3看1:

    1. countDown调用releaseShared方法,如果此时state是1,对其进行减-1操作后为0,tryReleaseShared将返回true,此时调用doReleaseShared方法唤醒队列中的线程,因为唤醒后的线程是调用
      tryAcquireShared方法,该方法不会改变state状态,只会返回1,返回1会继续唤醒后续线程,直到所有线程都被唤醒为止(因为所有的节点都是以share mode方式放入队列的),这部分逻辑在doAcquireSharedInterruptibly方法中,因为之前已经阅读过AQS源码了,这里就不再看这个方法源码了;

    2. 如果此时state不为1,那么state减完后 != 0,那么tryReleaseShared返回false,方法执行就结束了,不会产生更多的影响;

  5. 结合以上理解,所以这里有个大胆的想法,如果state给一个负值会如何,看看构造函数,限制了参数 <0的情况,会抛出IllegalArgumentException,那等于0会如何?await的线程会直接返回,那么调用countDown,是否会将state 减为负值呢?看到tryReleaseShared方法其实也对state == 0的情况做了判断,直接返回false,不会对其减一,也就意味着如果state已经== 0了,countDown是不会再对state--的,因为返回false的缘故,也不会再去唤醒等待队列中的线程;

你可能感兴趣的:(24 CountdownLatch)