CountDownLatch 源码分析

110 阅读1分钟
/**
  设置成员变量 state =2
**/
CountDownLatch countDownLatch = new CountDownLatch(2);
public CountDownLatch(int count) 
{
    if (count < 0) throw new IllegalArgumentException("count < 0");
    this.sync = new Sync(count);
}

Sync 内部类源码

private static final class Sync extends AbstractQueuedSynchronizer 
{
    private static final long serialVersionUID = 4982264981922014374L;

    Sync(int count) 
    {
        setState(count);
    }

    int getCount() 
    {
        return getState();
    }

    // 调用await()方法中会用到
    protected int tryAcquireShared(int acquires) 
    {
        return (getState() == 0) ? 1 : -1;
    }
    
    /**
      计数器-1
    **/
    protected boolean tryReleaseShared(int releases) 
    {
        // Decrement count; signal when transition to zero
        for (;;) 
        {
            // 获取state的值 如果是0 表示没有值可减了 
            int c = getState();
            if (c == 0)
                // state -1 失败 结束死循环
                return false;
            // 要更新的值    
            int nextc = c-1;
            // CAS 更新state  更新成功
            if (compareAndSetState(c, nextc))
               //判断nextc 值是否等于 0  如果等于0 返回true
               // 不等于0 返回false
               //结束死循环
                return nextc == 0;
        }
    }
}

countDown()

public void countDown() {
    sync.releaseShared(1);
}

AQS releaseShared

public final boolean releaseShared(int arg) 
{
    /**
      tryReleaseShared  返回值是true 表示state刚好是由1-1 = 0 的时候
       其他情况是false
    **/
    if (tryReleaseShared(arg)) 
    {
        // aqs 类中定义的方法
        doReleaseShared();
        return true;
    }
    // 计数器-1 失败
    return false;
}

doReleaseShared

private void doReleaseShared() {
    
    /**
       当线程把state 从1-0的线程会执行这个方法 唤醒 因为执行await方法阻塞的线程
    **/
    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;
    }
}

await 阻塞线程方法

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

aqs 中定义acquireSharedInterruptibly

public final void acquireSharedInterruptibly(int arg)
        throws InterruptedException 
{
    if (Thread.interrupted())
        // 如果线程中断了  抛出异常
        throw new InterruptedException();
    if (tryAcquireShared(arg) < 0)
        // 判断state 的值 执行的是 countDownLatch 中自己定义的方法
        // state>0 返回-1  state=0 返回1
        // 当tryAcquireShared 返回-1执行doAcquireSharedInterruptibly方法
        doAcquireSharedInterruptibly(arg);
}

aqs中定义 doAcquireSharedInterruptibly

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);
                    //节点作废
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
            }
            // CAS 设置首节点的waitStatus=-1 为啥要设置是释放锁的时候 会判断
            // 要唤醒的线程的waitStatus 是否是-1
            if (shouldParkAfterFailedAcquire(p, node) &&
                // 这里线程会被阻塞 就是代码卡住在这里不会在执行了
                parkAndCheckInterrupt())
                throw new InterruptedException();
        }
    } 
    finally 
    {
        if (failed)
            cancelAcquire(node);
    }
}

shouldParkAfterFailedAcquire 阻塞线程

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) 
{
    int ws = pred.waitStatus;
    if (ws == Node.SIGNAL)
        /*
         * This node has already set status asking a release
         * to signal it, so it can safely park.
         */
        return true;
    if (ws > 0) {
        /*
         * Predecessor was cancelled. Skip over predecessors and
         * indicate retry.
         */
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
        /*
         * waitStatus must be 0 or PROPAGATE.  Indicate that we
         * need a signal, but don't park yet.  Caller will need to
         * retry to make sure it cannot acquire before parking.
         */
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

setHeadAndPropagate 等待队列中的线程如何唤醒的?

private void setHeadAndPropagate(Node node, int propagate) 
{
    // propagate =1 node 第一个节点
    Node h = head; // Record old head for check below
    // 新节点成为头节点
    setHead(node);
    /*
     * Try to signal next queued node if:
     *   Propagation was indicated by caller,
     *     or was recorded (as h.waitStatus either before
     *     or after setHead) by a previous operation
     *     (note: this uses sign-check of waitStatus because
     *      PROPAGATE status may transition to SIGNAL.)
     * and
     *   The next node is waiting in shared mode,
     *     or we don't know, because it appears null
     *
     * The conservatism in both of these checks may cause
     * unnecessary wake-ups, but only when there are multiple
     * racing acquires/releases, so most need signals now or soon
     * anyway.
     */
    if (propagate > 0 || h == null || h.waitStatus < 0 ||
        (h = head) == null || h.waitStatus < 0) {
        Node s = node.next;
        if (s == null || s.isShared())
            // 递归唤醒线程
            doReleaseShared();
    }
}