AbstractQueuedSynchronizer 源码自学笔记

Provides a framework for implementing blocking locks and related synchronizers (semaphores, events, etc) that rely on first-in-first-out (FIFO) wait queues. This class is designed to be a useful basis for most kinds of synchronizers that rely on a single atomic int value to represent state. Subclasses must define the protected methods that change this state, and which define what that state means in terms of this object being acquired or released. Given these, the other methods in this class carry out all queuing and blocking mechanics. Subclasses can maintain other state fields, but only the atomically updated int value manipulated using methods getState, setState and compareAndSetState is tracked with respect to synchronization.

提供了实现依赖于先进先出(FIFO)等待队列的阻塞锁和相关同步器(如信号量、事件等)的框架。此类旨在成为大多数依赖于单个原子 int 值表示状态的同步器的基础。子类必须定义受保护的方法,这些方法用于更改此状态,并定义该状态在获取或释放此对象时的含义。在定义了这些方法之后,此类中的其他方法将处理所有的排队和阻塞机制。子类可以维护其他状态字段,但只有通过 getState、setState 和 compareAndSetState 方法原子更新的 int 值才会在同步中被跟踪。

static final class Node {

        /** 
        * Marker to indicate a node is waiting in shared mode 
        * 标记 表明一个节点在共享模式下等待
        */
        static final Node SHARED = new Node();
        /** 
        * Marker to indicate a node is waiting in exclusive mode 
        * 标记 表明一个节点在独占模式下等待
        */
        static final Node EXCLUSIVE = null;

        /** 
        * waitStatus value to indicate thread has cancelled 
        * 字段 waitStatus 的一个枚举值,表明当前节点已经被取消了
        * This node is cancelled due to timeout or interrupt.
        * Nodes never leave this state. In particular,
        * a thread with cancelled node never again blocks.
        * 这个节点由于超时或者中断被取消了,变为这个状态以后就不会再变了
        * 尤其是被取消的节点永远不会再次被阻塞
        */
        static final int CANCELLED =  1;

        /** 
        * waitStatus value to indicate successor's thread needs unparking 
        * 字段 waitStatus 的一个枚举值,表明后继节点需要唤醒
        * The successor of this node is (or will soon be)
        * blocked (via park), so the current node must
        * unpark its successor when it releases or
        * cancels. To avoid races, acquire methods must
        * first indicate they need a signal,
        * then retry the atomic acquire, and then,on failure, block.
        * 这个节点的后继节点已经被阻塞了,或者马上就要被阻塞了,(这里提到的阻塞
        * 都是指通过LockSupport.part挂起了),那么当前节点在自己释放了同步,
        * 或者自己被取消的时候,唤醒它的后继节点。为了避免竞争,acquire方法(获取
        * 同步的方法)必须首先表明它们需要被唤醒(也就是将前驱节点标记为SIGNAL),
        * 然后再去尝试原子获取同步,如果获取失败,阻塞
        * 这里的需要被唤醒是指获取同步失败被阻塞后需要被前驱节点唤醒。
        * 
        */
        static final int SIGNAL    = -1;

        /** 
        * waitStatus value to indicate thread is waiting on condition 
        * 字段 waitStatus 的一个枚举值,表明线程在等待一个
        * This node is currently on a condition queue.
        * It will not be used as a sync queue node
        * until transferred, at which time the status
        * will be set to 0. (Use of this value here has
        * nothing to do with the other uses of the
        * field, but simplifies mechanics.)
        * 这个节点当前在一个 condition 队列中,直到被转移(转移到同步队列),
        * 这个节点才会被当作一个同步队列的节点使用,这时waitStatus将会被
        * 设置为0. 使用这个值与这个字段的其他使用无关,只是为了简化机制
        * 
        */
        static final int CONDITION = -2;

        /**
        * waitStatus value to indicate the next acquireShared should
        * unconditionally propagate
        *
        * A releaseShared should be propagated to other
        * nodes. This is set (for head node only) in
        * doReleaseShared to ensure propagation
        * continues, even if other operations have
        * since intervened.
        * 当一个线程释放共享后,应该被传播到其他节点。这是在 doReleaseShared 
        * 中设置的(只对头节点设置),确保传播的继续,即使自那以来有其他操作已经介入
        * ”这部分指的是在 doReleaseShared 方法执行期间,可能存在其他线程的活动
        * 或系统事件(如中断、上下文切换等),这些都可能影响同步器的状态或等待队
        * 列的状态。然而,通过设置(在 doReleaseShared 中进行)来确保释放操作的
        * 传播不受这些外部操作的影响,从而保持了同步器的稳定性和一致性。
        */
        static final int PROPAGATE = -3;

        /**
         *
         * The values are arranged numerically to simplify use.
         * Non-negative values mean that a node doesn't need to
         * signal. So, most code doesn't need to check for particular
         * values, just for sign.
         * 这些值是按照数值拍列的为了简化使用,非负数代表一个节点不需要唤醒
         * 后继节点。因此在编码时大部分都不需要检查特殊的值,判断正负就可以了
         * The field is initialized to 0 for normal sync nodes, and
         * CONDITION for condition nodes.  It is modified using CAS
         * (or when possible, unconditional volatile writes).
         * 对于常规的同步节点,这个字段会被初始化为0,条件节点初始化为 
         * CONDITION = -2 。改变是通过 cas 来改变的(或者可能的话,无条件volatile
         *  writes)
         */
        volatile int waitStatus;

        /**
         * Link to predecessor node that current node/thread relies on
         * for checking waitStatus. Assigned during enqueuing, and nulled
         * out (for sake of GC) only upon dequeuing.  Also, upon
         * cancellation of a predecessor, we short-circuit while
         * finding a non-cancelled one, which will always exist
         * because the head node is never cancelled: A node becomes
         * head only as a result of successful acquire. A
         * cancelled thread never succeeds in acquiring, and a thread only
         * cancels itself, not any other node.
         * 这个字段指向前驱节点,当前线程(或者节点)依靠它来检查 waitStatus 的值,
         * 在入等待队列的过程中赋值,一出队就置为null,为了方便垃圾回收。
         * 同样当我们在寻找一个未取消的节点时,一旦一个前驱节点被取消了,我们就
         * 短路(跳过被取消的节点),因为头节点永远不会被取消,所以总能找到一个未被
         * 取消的节点(意思就是最差也能找到头节点这个未被取消的前驱节点)。
         * 一个节点只有在 acquire 成功的情况下才会变成头节点,一个被取消的线程
         * 永远不会 acquire 成功,一个线程只能取消它自己所属Node,不能取消任何其他
         * Node
         */
        volatile Node prev;

        /**
         * Link to the successor node that the current node/thread
         * unparks upon release. Assigned during enqueuing, adjusted
         * when bypassing cancelled predecessors, and nulled out (for
         * sake of GC) when dequeued.  The enq operation does not
         * assign next field of a predecessor until after attachment,
         * so seeing a null next field does not necessarily mean that
         * node is at end of queue. However, if a next field appears
         * to be null, we can scan prev's from the tail to
         * double-check. The next field of cancelled nodes is set to
         * point to the node itself instead of null, to make life
         * easier for isOnSyncQueue.
         * 这个字段指向后继节点,当前节点一旦 release ,就需要唤醒该后继节点。
         * 该节点的后继节点入队过程中给其赋值,绕过取消的前驱节点时会对该字段
         * 的指向进行调整,出队的时候将该字段职位null,为了方便垃圾回收。
         * 入队(enq)操作在 attachment 之前是不会给next字段赋值的,这里的
         * attachment 指的是将要入队Node的pre指向之前的尾节点,再通过cas将
         * tail 指向要入队的节点,这两部合起来才算 attachment 成功。因此如果
         * 看到一个Node的next==null,就没必要必须意味着这个节点是队列的尾节点,
         * 换一个说法就是next==null 并不一定意味着是队列的尾节点,因为如果一
         * 个节点刚完成 attachment 还未来得及将前驱节点next指向自己,那么它的
         * 前驱节点的next还是null,但是完成了 attachment 之后就有可能有其他Node
         * 追加到这个节点的后面。如果出现一个Node的next==null,我们可以从队列
         * 尾部往前进行二次检测。被取消节点的next会指向节点自己而不是置为null,
         * 使得 isOnSyncQueue 方法更简单高效
         */
        volatile Node next;

        /**
         * The thread that enqueued this node.  Initialized on
         * construction and nulled out after use.
         * 将当前节点入队的线程,创建节点对象的初始化,使用完了之后
         * 置为null
         */
        volatile Thread thread;

        /**
         * Link to next node waiting on condition, or the special
         * value SHARED.  Because condition queues are accessed only
         * when holding in exclusive mode, we just need a simple
         * linked queue to hold nodes while they are waiting on
         * conditions. They are then transferred to the queue to
         * re-acquire. And because conditions can only be exclusive,
         * we save a field by using special value to indicate shared
         * mode.
         * 指向等待条件的下一个Node,或者指向特殊值SHARED。因为只有在持有
         * 排他锁的情况下,才能够访问条件队列,我们只需要一个简单的链表队列
         * 就可以持有正在等待某个条件的多个Node。这些等待条件的Node之后会被
         * 转移到同步队列去重新获取锁。
         * 因为条件只能是排他的,所以我们用一个字段保存一个特殊的值来表明共享
         * 模式
         */
        Node nextWaiter;

        /**
         * Returns true if node is waiting in shared mode.
         * 如果节点正在以共享模式等待 返回 true
         */
        final boolean isShared() {
            return nextWaiter == SHARED;
        }

        /**
         * Returns previous node, or throws NullPointerException if null.
         * Use when predecessor cannot be null.  The null check could
         * be elided, but is present to help the VM.
         * 返回前驱节点,如果前驱节点为null,抛出空指针异常。当前驱节点不可能
         * 为null的情况下,可以使用该方法。空检查可以省略,但存在是为了帮助VM
         * 
         * @return the predecessor of this node
         */
        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

        Node() {    // Used to establish initial head or SHARED marker
        }

        Node(Thread thread, Node mode) {     // Used by addWaiter
            this.nextWaiter = mode;
            this.thread = thread;
        }

        Node(Thread thread, int waitStatus) { // Used by Condition
            this.waitStatus = waitStatus;
            this.thread = thread;
        }


}
/**
 * Head of the wait queue, lazily initialized.  Except for
 * initialization, it is modified only via method setHead.  Note:
 * If head exists, its waitStatus is guaranteed not to be
 * CANCELLED.
 * 等待队列的头,延迟初始化。除了初始化,只可以通过setHead方法修改
 * 注意:如果 head 存在,它的 waitStatus 保证不能是 CANCELLED
 * 
 */
private transient volatile Node head;

/**
 * Tail of the wait queue, lazily initialized.  Modified only via
 * method enq to add new wait node.
 * 等待队列的尾,延迟初始化。只可以通过 enq 方法添加新的等待节点来修改
 * 
 */
private transient volatile Node tail;

/**
 * The synchronization state.
 * 同步状态
 */
private volatile int state;

 java.util.concurrent.locks.AbstractQueuedSynchronizer#enq

 /**
 * Inserts node into queue, initializing if necessary. See picture above.
 * 给队列插入节点,如果队列为空就顺带初始化
 * @param node the node to insert
 * @return node's predecessor
 */
private Node enq(final Node node) {
    //这里实现的是一个自旋入队,直到成功入队为止
    for (;;) {
        Node t = tail;
        if (t == null) { // Must initialize
            // 尾节点为null,说明队列还未初始化,这里进行初始化
            // 创建一个空节点(节点的thread为null),waitStatus默认为0
            // 将头和尾 都指向这个新创建的节点
            // 这里使用 cas 的方式设置头节点,是为了保证只能有一个线程初始化
            // 如果一个线程成功将 head 指向新创建的node,其他线程就会失败,只有
            // 成功的线程才能进入 if 将tail指向这个节点。失败的线程进入下一次循环
            // 执行 else 逻辑,成功的线程初始化完了之后,也进入下一次循环,执行else
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            // 这里先将要添加的Node的前驱节点指向尾节点 也就是前面提到的 attachment
            // 操作的第一步
            node.prev = t;

       // 这里是 attachment 的第二部,通过 cas 将尾节点指向要添加的节点,这里使用
       // cas 是因为可能同时有多个线程需要入队,多个线程可能都已经完成了 attachment
       // 的第一步,都将要插入的Node的前驱节点指向同一个尾节点,所以这里必须保证只有
       // 一个线程能够成功将 tail 指向自己要插入的节点,成功的节点会将前驱节点的next
       // 指向自己,形成双向列表,其他线程都会失败,然后进入下次循环,拉去最新的尾节点
       // ,重新执行上面的逻辑。
       // 这里有个问题,就是通常我们判断一个列表的尾节点,是根据这个节点的next是否为null
       // 如果为null,就认为是尾节点。但是这里会有一种特殊情况,就是一个节点的next为null
       // 但是它却不是尾节点。具体的情况是,假如之前队列的尾节点是线程A添加的节点,这时B
       // 线程要添加一个新节点,刚完成attachment,也就是B.pre=A,tail=B,但是还未完成
       // A.next=B,这时A.next==null。这时有线程C也要添加新节点,发现tail==B,所以 
       // 直接就追加到B的后面。
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}

 java.util.concurrent.locks.AbstractQueuedSynchronizer#addWaiter

/**
 * Creates and enqueues node for current thread and given mode.
 * 为当前线程创建一个Node节点对象,并且入到等待队列,并且可以指定节点
 * 是 独占模式 还是 共享模式
 * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
 * @return the new node
 */
private Node addWaiter(Node mode) {
    Node node = new Node(Thread.currentThread(), mode);
    // Try the fast path of enq; backup to full enq on failure
    // 先尝试一次快速入队,如果快速入队失败了,就回到自旋入队
    // 这里快速入队逻辑其实和自旋入队基本一样,只不过这里在判断尾节点不为null
    // 也就是队列已经初始化情况下才会尝试快速入队,如果队列还未初始化,就要走
    // 自旋入队方法 enq 的逻辑,enq 中会对队列进行初始化
    Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    enq(node);

    //这里返回的就是新创建,并且完成入队的新节点
    return node;
}

 java.util.concurrent.locks.AbstractQueuedSynchronizer#setHead

/**
 * Sets head of queue to be node, thus dequeuing. Called only by
 * acquire methods.  Also nulls out unused fields for sake of GC
 * and to suppress unnecessary signals and traversals.
 * 将队列的head设置为传入的node节点,从而将原来的头节点出队。只会在
 * aquire 方法中会被调用。同时也会将没用的字段置为null,为了垃圾
 * 回收,并且可以抑制没必要的唤醒和遍历。
 * 
 * 
 * @param node the node
 */
private void setHead(Node node) {
    head = node;
    // 因为node被设置为头节点,肯定是当前线程 acquire 成功了,有可能是成功
    // 获取了独占锁,也有可能成功获取了共享锁,反正接下来就因该是获取锁的逻辑
    // 返回,然后执行需要同步(需要上锁)的业务代码。所以这时候 node 节点就变成
    // 了一个象征意义的头节点
    // 执行完需要同步的代码,释放锁,这时候只需要通过头节点的next的找到下一个
    // 等待获取锁的节点进行唤醒

    // 介于上述,这里的 prev 置为null可以防止没必要的遍历
    // thread 也不会再用到了 置为 null 
    node.thread = null;
    node.prev = null;
}

 java.util.concurrent.locks.AbstractQueuedSynchronizer#unparkSuccessor

 /**
 * Wakes up node's successor, if one exists.
 * 这里是唤醒指定Node节点的后继节点所持有的线程,前提是这个节点有
 * 后继节点,在释放锁之后进行,以便让其后继节点参与争取锁
 * @param node the node
 */
private void unparkSuccessor(Node node) {
    /*
     * If status is negative (i.e., possibly needing signal) try
     * to clear in anticipation of signalling.  It is OK if this
     * fails or if status is changed by waiting thread.
     * 如果这个节点的 waitStatus 是一个负数(负数表示可能需要唤醒后继节点),
     * 就尝试消除唤醒的期望,因为接下来的逻辑就是要完成唤醒后继节点,唤醒
     * 后继节点之后,这个头节点就没用了,如果后继节点持有的线程成功获取到
     * 锁,就会通过setHead()将头节点指向自己,这样node这个原来的head
     * 就会被垃圾回收掉
     * 这里就算修改失败或者 waitStatus 被等待线程修改了也没事
     * 
     */
    int ws = node.waitStatus;
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);

    /*
     * Thread to unpark is held in successor, which is normally
     * just the next node.  But if cancelled or apparently null,
     * traverse backwards from tail to find the actual
     * non-cancelled successor.
     * 需要被唤醒的线程对象被后继节点所持有,正常情况下就是下一个,
     * 但是如果遇到后继节点被取消,或者为null,这里的为null可能有
     * 两种情况,一种是当前节点已经是尾节点,没有后继节点了,另一种
     * 是后继节点还没来得及将其前驱节点的next指向自己。所以如果遇到
     * 后继节点被取消或者后继节点为null的情况,就从尾部开始往回遍历
     * 找一个确实没有被取消的后继节点
     */

    // 这里申明的 s 就是要指向最终要唤醒的节点
    Node s = node.next;
    // s.waitStatus > 0  后继节点已经被取消
    // s == null 没有后继节点或者后继节点还没有将前驱节点的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;
    }
    
    //s != null 说明找到了未取消的后继节点,对其所持有的线程进行唤醒
    if (s != null)
        LockSupport.unpark(s.thread);
}

 java.util.concurrent.locks.AbstractQueuedSynchronizer#cancelAcquire

 /**
 * Cancels an ongoing attempt to acquire.
 * 取消node节点所持有的线程正在进行的获取锁行为
 * 该方法只在 acquire失败之后调用,
 * 1.如果一个节点在等待锁时设置了超时时间,并且在超时时间内未能
 * 获取到锁,该节点会被取消
 * tryAcquireNanos 方法允许节点在尝试获取锁时设置超时时间。
 * 如果在超时时间内未能获取到锁,节点会放弃等待,并返回 false
 * 
 * 2.如果一个节点在等待锁时被中断,该节点会被取消
 * acquireInterruptibly 方法允许节点在等待锁时被中断。
 * 如果节点被中断,会抛出 InterruptedException,节点会放弃等待
 * 
 * 3.如果一个节点在尝试获取锁时失败(例如,由于资源不足或其他原因),
 * 该节点可能会被取消
 * acquireQueued 方法种 tryAcquire 调用抛出异常
 * 
 * @param node the node
 */
private void cancelAcquire(Node node) {
    // Ignore if node doesn't exist
    // 如果要取消的 node 为null 结束
    // 这里不明白为啥要做这个校验,调用这个方法的地方都是通过new
    // 创建的Node对象,不会是null
    if (node == null)
        return;

    // 先把node节点所持有的线程置为null,因为节点被取消之后
    // 会从队列中移除,node.thread = null 帮助垃圾回收
    // 此时还未将节点的 waitStatus 修改为CANCELLED,还有可能
    // 被其他线程进行没必要的唤醒,node.thread = null可以避免
    // 这些没必要的唤醒
    node.thread = null;

    // 要取消当前节点需要找到前驱节点,因为前驱节点可能已经被取消
    // 所以这里往前遍历,跳过被取消节点,找到一个未被取消的前驱节点
    // Skip cancelled predecessors
    Node pred = node.prev;
    while (pred.waitStatus > 0)
        node.prev = pred = pred.prev;

    // predNext is the apparent node to unsplice. CASes below will
    // fail if not, in which case, we lost race vs another cancel
    // or signal, so no further action is necessary.
    // predNext 很明显是需要被移除的那个节点,这里有可能需要移除的节点
    // 不止一个,从node到predNext都是需要被移除的节点,因为pred是从node
    // 开始往前遍历遇到的第一个未取消的节点,所以他们之间的节点都是被取消的

    // 如果不是,下面的cas将会失败,这种情况下说明我们在与其他 线程的取消
    // 操作或者唤醒操作的竞争中输了,所以不需要再做其他操作了
    // 换种说法就是,如果predNext不是需要被移除的节点,肯定是其他线程在
    // 执行取消操作或者唤醒操作时已经将其移除了,这样下面的cas发现predNext
    // 变了就会失败
    Node predNext = pred.next;

    // Can use unconditional write instead of CAS here.
    // After this atomic step, other Nodes can skip past us.
    // Before, we are free of interference from other threads.
    // 在这里可以使用无条件写入而不是通过cas写入。因为这里的最终
    // 目的就是要把node的状态修改尾CANCELLED,就算其他线程已经将其
    // 状态修改,这里也可以将其覆盖。修改完了之后,其他线程在取消
    // 或者唤醒操作时都会跳过我们,最终我们会被移除。
    // 修改之前我们的状态还是默认值 0 ,所以不会受其他线程的干扰
    // 也就是不会被其他线程移除。
    node.waitStatus = Node.CANCELLED;

    // If we are the tail, remove ourselves.
    // 如果我们是尾节点,直接把我们移除就可以了,这里使用的删除方法
    // 是,先通过cas将tail指向之前尾节点的前驱节点,如果成功,将其
    // 前驱节点的next置为null,这样尾节点就没有被引用最后被垃圾回收 
    if (node == tail && compareAndSetTail(node, pred)) {
        // 这里将前驱节点的next置为null,也是通过cas操作的,为了防止覆盖,
        // 比如:我们第一步把tail指向前驱节点,还未完成将前驱节点的next置
        // 为null的时候,正好有一个节点要入队,就把前驱节点当作tail追加在
        // 其后面,并将前驱节点的next指向了新入队的节点,这时通过cas操作时,
        // 所以就发现前驱节点的next已经改变了,所以就修改失败了,避免了将新
        // 入队的节点丢失
        compareAndSetNext(pred, predNext, null);
    } else {
        // 执行到这里有两种情况1.node本来就不是尾节点 2.node本来是尾节点,但是
        // 在将尾节点指向其前驱节点之前,有其他线程的节点入队追加到到node后面
        // 导致尾节点变成了新入队的节点,这样compareAndSetTail(node, pred)
        // 就失败了。这两种情况下,node都会有后继节点

        // If successor needs signal, try to set pred's next-link
        // so it will get one. Otherwise wake it up to propagate.
        // 接下来的逻辑就是判断如果node的后继节点需要被唤醒,就把前面找到那个
        // 未取消前驱节点的next指向后继节点的,这样他将会收到一个前驱节点的唤醒
        // ,这里的get one 就是获取到一个被唤醒的操作。
        // 否则,唤醒后继节点以传播信号,这里的 it 指的是后继节点
        int ws;
        if (pred != head &&
            ((ws = pred.waitStatus) == Node.SIGNAL ||
             (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
            pred.thread != null) {

            //执行到这里说明同时满足以下三个条件,那么前驱节点最后肯定能唤醒后继节点
            //1.前驱节点不是头节点
            //这里的原因是,如果前驱节点不是头节点,说明前驱节点有两种情况,
            //第一种是正在阻塞等待它的前驱节点唤醒,他如果被唤醒抢到锁,执行完,释放锁的
            //时候肯定也会唤醒它的后继节点
            //第二种是,前驱节点正在获取锁或者刚获取到但是还没执行setHead方法
            //,这种情况如果获取锁失败继续阻塞又和第一种一样了,如果获取锁成功了,说明
            //被锁的代码块和释放锁的操作还没执行,所以它执行完了也会唤醒后继节点

            //2.前驱节点的状态本来就是SIGNAL,或者被成功修改为SIGNAL


            //3.pred.thread != null 
            //必须满足这个条件是因为,前驱节点如果是 阻塞被中断,或者阻塞获取锁的时间超时
            //就有可能被取消,被取消的方法的首先会将被取消节点的thread置为null,所以这里
            //通过判断pred.thread != null 来表示前驱节点未被取消

            Node next = node.next;
            
            // 这里判断后继节点存在且没有被取消,所以需要唤醒
            // 这里也是通过cas修改,防止前驱节点的next已经被其他线程的 取消操作
            // 或者 唤醒操作 指向了其他节点,已经不再是 predNext
            if (next != null && next.waitStatus <= 0)
                compareAndSetNext(pred, predNext, next);
        } else {
            //1.如果前驱节点为头节点
            //2.如果pred.waitStatus != Node.SIGNAL 
            //  并且 compareAndSetWaitStatus(pred,ws,Node.SIGNAL)失败
            //3.如果pred.thread == null
            // 三个条件满足一个,唤醒被取消的节点 node 的后继节点
            unparkSuccessor(node);
        }

        node.next = node; // help GC
    }
}

 java.util.concurrent.locks.AbstractQueuedSynchronizer#shouldParkAfterFailedAcquire

/**
 * Checks and updates status for a node that failed to acquire.
 * Returns true if thread should block. This is the main signal
 * control in all acquire loops.  Requires that pred == node.prev.
 *
 * @param pred node's predecessor holding status
 * @param node the node
 * @return {@code true} if thread should block
 */
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;
}

/**
 * Convenience method to interrupt current thread.
 */
static void selfInterrupt() {
    Thread.currentThread().interrupt();
}

/**
 * Convenience method to park and then check if interrupted
 *
 * @return {@code true} if interrupted
 */
private final boolean parkAndCheckInterrupt() {
    LockSupport.park(this);
    return Thread.interrupted();
}

 java.util.concurrent.locks.AbstractQueuedSynchronizer#acquireQueued

/*
 * Various flavors of acquire, varying in exclusive/shared and
 * control modes.  Each is mostly the same, but annoyingly
 * different.  Only a little bit of factoring is possible due to
 * interactions of exception mechanics (including ensuring that we
 * cancel if tryAcquire throws exception) and other control, at
 * least not without hurting performance too much.
 */

/**
 * Acquires in exclusive uninterruptible mode for thread already in
 * queue. Used by condition wait methods as well as acquire.
 *
 * @param node the node
 * @param arg the acquire argument
 * @return {@code true} if interrupted while waiting
 */
final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

 java.util.concurrent.locks.AbstractQueuedSynchronizer#tryAcquire

/**
 * Attempts to acquire in exclusive mode. This method should query
 * if the state of the object permits it to be acquired in the
 * exclusive mode, and if so to acquire it.
 *
 * <p>This method is always invoked by the thread performing
 * acquire.  If this method reports failure, the acquire method
 * may queue the thread, if it is not already queued, until it is
 * signalled by a release from some other thread. This can be used
 * to implement method {@link Lock#tryLock()}.
 *
 * <p>The default
 * implementation throws {@link UnsupportedOperationException}.
 *
 * @param arg the acquire argument. This value is always the one
 *        passed to an acquire method, or is the value saved on entry
 *        to a condition wait.  The value is otherwise uninterpreted
 *        and can represent anything you like.
 * @return {@code true} if successful. Upon success, this object has
 *         been acquired.
 * @throws IllegalMonitorStateException if acquiring would place this
 *         synchronizer in an illegal state. This exception must be
 *         thrown in a consistent fashion for synchronization to work
 *         correctly.
 * @throws UnsupportedOperationException if exclusive mode is not supported
 */
protected boolean tryAcquire(int arg) {
    throw new UnsupportedOperationException();
}

/**
 * Attempts to set the state to reflect a release in exclusive
 * mode.
 *
 * <p>This method is always invoked by the thread performing release.
 *
 * <p>The default implementation throws
 * {@link UnsupportedOperationException}.
 *
 * @param arg the release argument. This value is always the one
 *        passed to a release method, or the current state value upon
 *        entry to a condition wait.  The value is otherwise
 *        uninterpreted and can represent anything you like.
 * @return {@code true} if this object is now in a fully released
 *         state, so that any waiting threads may attempt to acquire;
 *         and {@code false} otherwise.
 * @throws IllegalMonitorStateException if releasing would place this
 *         synchronizer in an illegal state. This exception must be
 *         thrown in a consistent fashion for synchronization to work
 *         correctly.
 * @throws UnsupportedOperationException if exclusive mode is not supported
 */
protected boolean tryRelease(int arg) {
    throw new UnsupportedOperationException();
}

 java.util.concurrent.locks.AbstractQueuedSynchronizer#acquire

/**
 * Acquires in exclusive mode, ignoring interrupts.  Implemented
 * by invoking at least once {@link #tryAcquire},
 * returning on success.  Otherwise the thread is queued, possibly
 * repeatedly blocking and unblocking, invoking {@link
 * #tryAcquire} until success.  This method can be used
 * to implement method {@link Lock#lock}.
 *
 * @param arg the acquire argument.  This value is conveyed to
 *        {@link #tryAcquire} but is otherwise uninterpreted and
 *        can represent anything you like.
 */
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

 java.util.concurrent.locks.AbstractQueuedSynchronizer#release

/**
 * Releases in exclusive mode.  Implemented by unblocking one or
 * more threads if {@link #tryRelease} returns true.
 * This method can be used to implement method {@link Lock#unlock}.
 *
 * @param arg the release argument.  This value is conveyed to
 *        {@link #tryRelease} but is otherwise uninterpreted and
 *        can represent anything you like.
 * @return the value returned from {@link #tryRelease}
 */
public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

java.util.concurrent.locks.AbstractQueuedSynchronizer#doReleaseShared

/**
 * Release action for shared mode -- signals successor and ensures
 * propagation. (Note: For exclusive mode, release just amounts
 * to calling unparkSuccessor of head if it needs signal.)
 */
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;
    }
}

java.util.concurrent.locks.AbstractQueuedSynchronizer#setHeadAndPropagate

/**
 * Sets head of queue, and checks if successor may be waiting
 * in shared mode, if so propagating if either propagate > 0 or
 * PROPAGATE status was set.
 *
 * @param node the node
 * @param propagate the return value from a tryAcquireShared
 */
private void setHeadAndPropagate(Node node, int propagate) {
    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();
    }
}

java.util.concurrent.locks.AbstractQueuedSynchronizer#doAcquireShared

/**
 * Acquires in shared uninterruptible mode.
 * @param arg the acquire argument
 */
private void doAcquireShared(int arg) {
    final Node node = addWaiter(Node.SHARED);
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            final Node p = node.predecessor();
            if (p == head) {
                int r = tryAcquireShared(arg);
                if (r >= 0) {
                    setHeadAndPropagate(node, r);
                    p.next = null; // help GC
                    if (interrupted)
                        selfInterrupt();
                    failed = false;
                    return;
                }
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

java.util.concurrent.locks.AbstractQueuedSynchronizer#tryAcquireShared

/**
 * Attempts to acquire in shared mode. This method should query if
 * the state of the object permits it to be acquired in the shared
 * mode, and if so to acquire it.
 *
 * <p>This method is always invoked by the thread performing
 * acquire.  If this method reports failure, the acquire method
 * may queue the thread, if it is not already queued, until it is
 * signalled by a release from some other thread.
 *
 * <p>The default implementation throws {@link
 * UnsupportedOperationException}.
 *
 * @param arg the acquire argument. This value is always the one
 *        passed to an acquire method, or is the value saved on entry
 *        to a condition wait.  The value is otherwise uninterpreted
 *        and can represent anything you like.
 * @return a negative value on failure; zero if acquisition in shared
 *         mode succeeded but no subsequent shared-mode acquire can
 *         succeed; and a positive value if acquisition in shared
 *         mode succeeded and subsequent shared-mode acquires might
 *         also succeed, in which case a subsequent waiting thread
 *         must check availability. (Support for three different
 *         return values enables this method to be used in contexts
 *         where acquires only sometimes act exclusively.)  Upon
 *         success, this object has been acquired.
 * @throws IllegalMonitorStateException if acquiring would place this
 *         synchronizer in an illegal state. This exception must be
 *         thrown in a consistent fashion for synchronization to work
 *         correctly.
 * @throws UnsupportedOperationException if shared mode is not supported
 */
protected int tryAcquireShared(int arg) {
    throw new UnsupportedOperationException();
}

/**
 * Attempts to set the state to reflect a release in shared mode.
 *
 * <p>This method is always invoked by the thread performing release.
 *
 * <p>The default implementation throws
 * {@link UnsupportedOperationException}.
 *
 * @param arg the release argument. This value is always the one
 *        passed to a release method, or the current state value upon
 *        entry to a condition wait.  The value is otherwise
 *        uninterpreted and can represent anything you like.
 * @return {@code true} if this release of shared mode may permit a
 *         waiting acquire (shared or exclusive) to succeed; and
 *         {@code false} otherwise
 * @throws IllegalMonitorStateException if releasing would place this
 *         synchronizer in an illegal state. This exception must be
 *         thrown in a consistent fashion for synchronization to work
 *         correctly.
 * @throws UnsupportedOperationException if shared mode is not supported
 */
protected boolean tryReleaseShared(int arg) {
    throw new UnsupportedOperationException();
}

java.util.concurrent.locks.AbstractQueuedSynchronizer#acquireShared 

/**
 * Acquires in shared mode, ignoring interrupts.  Implemented by
 * first invoking at least once {@link #tryAcquireShared},
 * returning on success.  Otherwise the thread is queued, possibly
 * repeatedly blocking and unblocking, invoking {@link
 * #tryAcquireShared} until success.
 *
 * @param arg the acquire argument.  This value is conveyed to
 *        {@link #tryAcquireShared} but is otherwise uninterpreted
 *        and can represent anything you like.
 */
public final void acquireShared(int arg) {
    if (tryAcquireShared(arg) < 0)
        doAcquireShared(arg);
}

java.util.concurrent.locks.AbstractQueuedSynchronizer#releaseShared

/**
 * Releases in shared mode.  Implemented by unblocking one or more
 * threads if {@link #tryReleaseShared} returns true.
 *
 * @param arg the release argument.  This value is conveyed to
 *        {@link #tryReleaseShared} but is otherwise uninterpreted
 *        and can represent anything you like.
 * @return the value returned from {@link #tryReleaseShared}
 */
public final boolean releaseShared(int arg) {
    if (tryReleaseShared(arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值