AQS笔记之Condition


Condition接口的一个实现类ConditionObject是AQS的内部类,每个Condition对象都包含一个队列,这个队列是Condition对象实现等待/通知的关键。
与Object的监视器模型(synchronized)中一个对象拥有一个同步队列和等待队列不同的是,J.U.C中AQS拥有一个同步队列和多个等待队列。

await方法

public final void await() throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            //这里不需要CAS操作,因为当前线程一定是获取到同步状态的线程(即同步队列的首节点)
            Node node = addConditionWaiter();//将同步队列中的当前线程构造成一个新的节点添加到等待队列尾部
            int savedState = fullyRelease(node);//释放node的同步状态并返回释放之前的同步状态
            int interruptMode = 0;
            while (!isOnSyncQueue(node)) {//判断当前节点是否已经在同步队列中
                //查看transferForSignal方法可知,下列情况线程将会被唤醒:
                // 1.同步队列的前继结点已取消
                // 2.设置同步队列的前继结点的状态为SIGNAL失败
                // 3.前继结点释放锁后唤醒当前结点
                LockSupport.park(this);//没有在同步队列中(即还在等待队列中),则阻塞(挂起)
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)//在等待过程中发生过中断则退出
                    break;
            }
            //线程在被唤醒之后采用独占式获取同步状态(恢复之前的同步状态)
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            //防止线程在signal之前发生了中断但是却没有从条件队列中移除
            if (node.nextWaiter != null) // clean up if cancelled
                unlinkCancelledWaiters();
            if (interruptMode != 0)//根据中断模式对中断进行响应
                reportInterruptAfterWait(interruptMode);
}

查看addConditionWaiter方法,fullyRelease方法,isOnSyncQueue方法,checkInterruptWhileWaiting方法,acquireQueued方法,unlinkCancelledWaiters方法

addConditionWaiter方法

private Node addConditionWaiter() {
            if (!isHeldExclusively())//判断同步器是否被当前线程所独占
                throw new IllegalMonitorStateException();
            Node t = lastWaiter;
            // If lastWaiter is cancelled, clean out.
            if (t != null && t.waitStatus != Node.CONDITION) {
                unlinkCancelledWaiters();//将当前等待队列中不处于等待状态(CONDITION)的节点移除
                t = lastWaiter;
            }

            Node node = new Node(Node.CONDITION);//将当前线程构造成新的等待队列节点

            //将当前节点添加到等待队列尾部
            if (t == null)
                firstWaiter = node;
            else
                t.nextWaiter = node;
            lastWaiter = node;//lastWaiter始终指向等待队列最后一个节点
            return node;
}

注意:在独占模式下,nextWaiter表示等待队列中的后继节点;在共享模式下,nextWaiter用SHARED常量表示,表示同步队列的共享模式节点。
查看unlinkCancelledWaiters方法
此方法被await方法调用

fullyRelease方法

final int fullyRelease(Node node) {
        try {
            int savedState = getState();
            if (release(savedState))
                return savedState;//若成功释放同步状态,则返回释放之前的同步状态
            throw new IllegalMonitorStateException();//若失败则抛出IllegalMonitorStateException异常
        } catch (Throwable t) {
            node.waitStatus = Node.CANCELLED;//抛出异常则将当前节点的等待状态变为CANCELLED
            throw t;
        }
}

查看release方法
此方法被await方法调用

isOnSyncQueue方法

final boolean isOnSyncQueue(Node node) {
        if (node.waitStatus == Node.CONDITION || node.prev == null)//
            return false;
        //next表示同步队列中的后继节点(nextWaiter表示等待队列中的后继节点),next不为null表示此节点已经在同步队列中
        if (node.next != null) // If has successor, it must be on queue
            return true;
        /*
         * node.prev can be non-null, but not yet on queue because
         * the CAS to place it on queue can fail. So we have to
         * traverse from tail to make sure it actually made it.  It
         * will always be near the tail in calls to this method, and
         * unless the CAS failed (which is unlikely), it will be
         * there, so we hardly ever traverse much.
         */
        return findNodeFromTail(node);//在同步队列中寻找node节点,若找到则返回true,没找到则返回false
    }

查看findNodeFromTail方法
此方法被await方法,transferAfterCancelledWait方法调用

unlinkCancelledWaiters方法

private void unlinkCancelledWaiters() {
            Node t = firstWaiter;
            Node trail = null;
            //遍历等待队列,将其中不处于等待状态(CONDITION)的节点从队列中移除
            while (t != null) {
                Node next = t.nextWaiter;
                if (t.waitStatus != Node.CONDITION) {
                    t.nextWaiter = null;
                    if (trail == null)
                        firstWaiter = next;
                    else
                        trail.nextWaiter = next;
                    if (next == null)
                        lastWaiter = trail;
                }
                else
                    trail = t;
                t = next;
            }
}

findNodeFromTail方法

private boolean findNodeFromTail(Node node) {
        // We check for node first, since it's likely to be at or near tail.
        // tail is known to be non-null, so we could re-order to "save"
        // one null check, but we leave it this way to help the VM.
        for (Node p = tail;;) {
            if (p == node)
                return true;
            if (p == null)
                return false;
            p = p.prev;
        }
}

查看findNodeFromTail方法
此方法被isOnSyncQueue方法调用

checkInterruptWhileWaiting方法

/**
  * Checks for interrupt, returning THROW_IE if interrupted
  * before signalled, REINTERRUPT if after signalled, or
  * 0 if not interrupted.
  */
private int checkInterruptWhileWaiting(Node node) {
    return Thread.interrupted() ?
        (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
        0;
}

查看transferAfterCancelledWait方法
此方法被await方法调用

transferAfterCancelledWait方法

final boolean transferAfterCancelledWait(Node node) {
        //CAS操作成功表明节点还在等待队列中(即signal之前)时发生了中断
        if (node.compareAndSetWaitStatus(Node.CONDITION, 0)) {
            enq(node);//注意在signal之前发生了中断,仅仅只是改变了node的等待状态并将其移动到同步队列,并未从等待队列中删除
            return true;
        }
        /*
         * If we lost out to a signal(), then we can't proceed
         * until it finishes its enq().  Cancelling during an
         * incomplete transfer is both rare and transient, so just
         * spin.
         */
        //在signal之后发生中断,但是此时还未将node移动到同步队列,那么先自旋等待
        while (!isOnSyncQueue(node))
            Thread.yield();
        return false;
}

查看isOnSyncQueue方法
此方法被checkInterruptWhileWaiting方法调用

signal方法

/**
  * Checks for interrupt, returning THROW_IE if interrupted
  * before signalled, REINTERRUPT if after signalled, or
  * 0 if not interrupted.
  */
public final void signal() {
            if (!isHeldExclusively())//判断当前线程是否独占同步状态
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
            if (first != null)
                doSignal(first);
 }

查看doSignal方法

doSignal方法

/**
  * Checks for interrupt, returning THROW_IE if interrupted
  * before signalled, REINTERRUPT if after signalled, or
  * 0 if not interrupted.
  */
private void doSignal(Node first) {
            //从首节点开始找到等待队列中第一个未被取消的节点转移到同步队列中
            do {
                if ( (firstWaiter = first.nextWaiter) == null)
                    lastWaiter = null;
                first.nextWaiter = null;
            } while (!transferForSignal(first) &&
                     (first = firstWaiter) != null);
}

查看transferForSignal方法调用
此方法被signal方法调用

transferForSignal方法

/**
  * Checks for interrupt, returning THROW_IE if interrupted
  * before signalled, REINTERRUPT if after signalled, or
  * 0 if not interrupted.
  */
final boolean transferForSignal(Node node) {
        /*
         * If cannot change waitStatus, the node has been cancelled.
         * 从前面的transferAfterCancelledWait方法可以看到在signal之前发生中断的节点线程并不会从等待队列中移除
         */
        if (!node.compareAndSetWaitStatus(Node.CONDITION, 0))
            return false;

        /*
         * Splice onto queue and try to set waitStatus of predecessor to
         * indicate that thread is (probably) waiting. If cancelled or
         * attempt to set waitStatus fails, wake up to resync (in which
         * case the waitStatus can be transiently and harmlessly wrong).
         */
        Node p = enq(node);
        int ws = p.waitStatus;
        //前驱节点被取消或者前驱节点状态更新为SIGNAL失败(意味着可能不会唤醒node节点)时,会唤醒node节点线程
        if (ws > 0 || !p.compareAndSetWaitStatus(ws, Node.SIGNAL))
            LockSupport.unpark(node.thread);
        return true;
}

查看enq方法
此方法被doSignal方法调用

enq方法

/**
  * Checks for interrupt, returning THROW_IE if interrupted
  * before signalled, REINTERRUPT if after signalled, or
  * 0 if not interrupted.
  */
  //将node节点插入同步队列尾部,并返回前驱节点
private Node enq(Node node) {
        for (;;) {
            Node oldTail = tail;
            if (oldTail != null) {
                node.setPrevRelaxed(oldTail);
                if (compareAndSetTail(oldTail, node)) {
                    oldTail.next = node;
                    return oldTail;
                }
            } else {
                initializeSyncQueue();
            }
        }
    }

此方法被transferAfterCancelledWait方法,transferForSignal方法调用

signalAll方法

/**
  * Moves all threads from the wait queue for this condition to
  * the wait queue for the owning lock.
  *
  * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
  *         returns {@code false}
  */
   public final void signalAll() {
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
            if (first != null)
                doSignalAll(first);
   }

查看doSignalAll方法

doSignalAll方法

/**
  * Removes and transfers all nodes.
  * @param first (non-null) the first node on condition queue
  */
  private void doSignalAll(Node first) {
      lastWaiter = firstWaiter = null;
       do {
           Node next = first.nextWaiter;
           first.nextWaiter = null;
           transferForSignal(first);
           first = next;
       } while (first != null);
  }

查看transferForSignal方法
此方法被signalAll方法调用

awaitUninterruptibly方法

public final void awaitUninterruptibly() {
            Node node = addConditionWaiter();
            int savedState = fullyRelease(node);
            boolean interrupted = false;
            while (!isOnSyncQueue(node)) {
                LockSupport.park(this);
                //线程被唤醒之后不会马上响应中断仅仅标记一下
                if (Thread.interrupted())
                    interrupted = true;
            }
            if (acquireQueued(node, savedState) || interrupted)
                selfInterrupt();
 }

查看addConditionWaiter方法,fullyRelease方法,isOnSyncQueue方法,acquireQueued方法
此方法被signalAll方法调用

回到顶部

你可能感兴趣的:(Java学习笔记)