8.await和signal源码

205 阅读11分钟

await源码

 public class ConditionObject implements Condition, java.io.Serializable {
        private static final long serialVersionUID = 1173984872572414699L;
        /** First node of condition queue. */
        private transient Node firstWaiter;
        /** Last node of condition queue. */
        private transient Node lastWaiter;
​
        /**
         * Creates a new {@code ConditionObject} instance.
         */
        public ConditionObject() { }
            
     
         public final void await() throws InterruptedException {
             if (Thread.interrupted())
                 throw new InterruptedException();
             Node node = addConditionWaiter();
             int savedState = fullyRelease(node);
             int interruptMode = 0;
             while (!isOnSyncQueue(node)) {
                 LockSupport.park(this);
                 if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                     break;
             }
             if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                 interruptMode = REINTERRUPT;
             if (node.nextWaiter != null) // clean up if cancelled
                 unlinkCancelledWaiters();
             if (interruptMode != 0)
                 reportInterruptAfterWait(interruptMode);
         }
     
        private Node addConditionWaiter() {
            Node t = lastWaiter;
            if (t != null && t.waitStatus != Node.CONDITION) {
                unlinkCancelledWaiters();
                t = lastWaiter;
            }
            Node node = new Node(Thread.currentThread(), Node.CONDITION);
            if (t == null)
                firstWaiter = node;
            else
                //只有1个指针nextWaiter
                //说明是1个单向队列
                t.nextWaiter = node;
            lastWaiter = node;
            return node;
        }
}
public class await {
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                lock.lock();
                try {
                    //10个线程依次获取锁,然后执行await方法
                    //此时这10个线程对应10个node放在队列里
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            });
            thread.start();
        }
    }
}

线程等待队列是双向链表即同步队列是双向链表,Codition等待队列是单链表

await

package test;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionObject implements Condition, java.io.Serializable {
    private static final long serialVersionUID = 1173984872572414699L;
    // 第一个等待节点 初始都是null
    private transient Node firstWaiter;
    // 最后一个等待节点 初始都是null
    private transient Node lastWaiter;
    
    public ConditionObject() { }
    
    //await方法
    public final void await() throws InterruptedException {
        //如果调用await的线程已经是中断状态抛出异常
        if (Thread.interrupted()){
            throw new InterruptedException();
        }
        
        //添加节点入Condition等待队列   
        //进入addConditionWaiter
        Node node = addConditionWaiter();
        
        // 释放当前线程所有的重入锁 并唤醒后继节点
        // 因为当前线程的锁释放后肯定要唤醒其他等待的节点去获取锁
        // 这说明了调用await方法必须是已经获得了condition引用(关联)的lock。
        int savedState = fullyRelease(node);
        //默认的打断模式是 0 即没有被打断
        int interruptMode = 0;
        /***
        isOnSyncQueue(node)判断是否在同步队列
        此时是不在同步队列:所以返回false
        !isOnSyncQueue(node)=true
        然后进入 LockSupport.park(this);阻塞
        **/
        while (!isOnSyncQueue(node)) {
            //将当前线程park
            LockSupport.park(this);
            //思考下:什么情况下会从park的状态解除?
            //1.当前线程被interrupt
            //2.当前线程被signal即LockSupport.unpark
            //当从park的状态解除以后,会调用checkInterruptWhileWaiting()方法
            //判断自己在park过程中有没有被中断过。
            //返回0表示没有被中断过 
            //返回THROW_IE = -1 表示需要抛出异常,因为只有在signal之前才能cas将0变成-2,进入同步队列成功。
            //返回1表示需要重置中断标识
            /***
            思考:什么时候会在同步队列?即什么时候跳出循环?    
            1.当前节点被移动到同步队列,即其他线程调用condition的signal或者signalAll,并把当前节点加入同步队列并修改状态为0
            2.在signal方法之前或者之后被interrupt,interruptMode!=0主动执行break;跳出循环
            如果是signal方法之前被interrupt 返回-1表示需要抛出异常 
            如果是signal方法之后被interrupt 返回1表示需要重置中断标识
            因为只有在signal之前的interrupt才能cas将0变成-2,进入同步队列成功。
            因为只有在signal之前的interrupt才能cas将0变成-2,进入同步队列成功。
            因为只有在signal之前的interrupt才能cas将0变成-2,进入同步队列成功。
            为什么?
            因为如果先执行signal,必然是由执行signal方法的线程把当前节点加入同步队列并修改状态为0
            否则cas是成功不了的
            当退出while循环后就会调用acquireQueued(node, savedState)
            acquireQueued的作用是在自旋过程中不断尝试获取同步状态,直至成功获取到lock。
            ***/
            if ((interruptMode = checkInterruptWhileWaiting(node)) != 0){
               break; 
            }
      
        }
        
        // 打断模式 - 在退出等待时重新设置打断状态
        // private static final int REINTERRUPT =  1;
        // 打断模式 - 在退出等待时抛出异常
        //private static final int THROW_IE = -1;
        
        //前提:(线程没有被打断并且被调用了signal方法被唤醒) 或者 (是在signal之后被打断)  
        //那么就尝试去获取锁
        //如果获取不到就继续在同步队列park阻塞直到获取到锁
        //如果获取到锁,并且打断是在signal之后
        //interruptMode = REINTERRUPT;
        //这里无视打断模式也是不可打断的体现
        if (acquireQueued(node, savedState) && interruptMode != THROW_IE){
             interruptMode = REINTERRUPT;
        }
        //当在同步队列中获取到锁继续往下走 如果当前节点的下一个节点 不为空 帮忙清理在等待队列被取消的节点
        // 清除等待队列中被取消的线程
        if (node.nextWaiter != null){
            unlinkCancelledWaiters();
        } 
        if (interruptMode != 0){
             //说明被打断
            reportInterruptAfterWait(interruptMode);
        }  
    }

addConditionWaiter:进入等待队列

// ㈠ 添加一个 Node 至等待队列
    private Node addConditionWaiter() {
        //获取最后一个节点
        Node t = lastWaiter;
        //Node.CONDITION=-2 表示结点等待在Condition上
        //不等于-2 代表 尾结点没有在condition等待队列上
        //
        if (t != null && t.waitStatus != Node.CONDITION) {
            //将所有已取消的 Node 从队列链表断开
            unlinkCancelledWaiters();
            t = lastWaiter;
        }
         // 这里很重要 这里很重要 这里很重要
        // 创建一个关联当前线程的新Node,并设置状态为-2   
        // 创建一个关联当前线程的新Node,并设置状态为-2 
        // 创建一个关联当前线程的新Node,并设置状态为-2 
        // 后面在判断节点在await的时候是否被interrupt,interrupt是在signal之前打断还是之后打断使用的是cas
        // 原始值就是Node.CONDITION=-2
        Node node = new Node(Thread.currentThread(), Node.CONDITION);
        
        //如果尾节点是空
        if (t == null)
            //将新加入的节点给头结点
            firstWaiter = node;
        else
            //将新加入的节点给尾节点的下一个节点
            //添加第一个node的时候n1即是头也是尾
            //添加第二个node的时候n1是头n2是尾 相当于将第二个节点n2放入头结点n1的下一个节点
            //添加第三个node的时候n3是尾相当于将第3个节点放入原尾结点n2的下一个节点
            //所以这里是个单向链表
            t.nextWaiter = node;
        
        //最后把lastWaiter指向新加入的node
        lastWaiter = node;
        return node;
    }
  private void unlinkCancelledWaiters() {
            //头结点
            Node t = firstWaiter;
            Node trail = null;
            while (t != null) {
                //头结点的下一个节点
                Node next = t.nextWaiter;
                //如果头结点的状态不是-2 需要出队
                if (t.waitStatus != Node.CONDITION) {
                    t.nextWaiter = null;
                    //将头结点的下一个节点作为新的头结点
                    if (trail == null)
                        firstWaiter = next;
                    else
                        trail.nextWaiter = next;
                    
                    //如果头结点的下一个节点是空 说明只有头结点
                    //将trail赋值给lastWaiter
                    if (next == null)
                        lastWaiter = trail;
                } else{
                    trail = t;
                }
                    
                t = next;
            }
        }

fullyRelease:释放锁

 // ㈣ 因为某线程可能重入,需要将 state 全部释放
    final int fullyRelease(Node node) {
        //此处的节点是要await的节点
        boolean failed = true;
        try {
            //注意这里释放的是多次加锁累加的state
            //注意这里释放的是多次加锁累加的state
            int savedState = getState();
            if (release(savedState)) {
                failed = false;
                return savedState;
            } else {
                throw new IllegalMonitorStateException();
            }
        } finally {
            //这里保证了异常也会被移除
            if (failed)
                node.waitStatus = Node.CANCELLED;
        }
    }
​
​
    //释放头节点
    public final boolean release(int arg) {
         //注意这里释放的是多次加锁累加的state
        if (tryRelease(arg)) {
            Node h = head;
            //头结点的waitStatus可能是0
            //原因是解锁的时候会用cas修改头结点的waitStatus=0
            //如果是0为什么不需要唤醒呢?
            // h == null 无等待队列
            // h.waitStatus == 0 说明后面没有阻塞的队列,即不需要唤醒。
            if (h != null && h.waitStatus != 0){
            //h是头节点
            //如果头结点的后置节点为空或被取消
            //从队列的末尾从后往前找,找到最前面一个需要unpark的节点
            //否则就唤醒头节点的下一个节点
                unparkSuccessor(h);
            }
            //释放成功返回true
            return true;
        }
        return false;
    }
     //尝试释放
      protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

unparkSuccessor:唤醒同步队列上的节点

private void unparkSuccessor(Node node) {
         //此处的node节点为头结点
        // 如果头节点状态为 小于0 尝试重置状态为 0
        // 尝试将node的等待状态置为0,这样的话,后继争用线程可以有机会再尝试获取一次锁。
        int ws = node.waitStatus;
        if (ws < 0) {
            compareAndSetWaitStatus(node, ws, 0);
        }
        //获取头结点的下一个节点
        Node s = node.next;
        //node是头结点
        //如果头结点的后置节点为空或被取消
        //从队列的末尾从后往前找,找到最前面一个需要unpark的节点
        //否则就唤醒头节点的下一个节点
        if (s == null || s.waitStatus > 0) {
            s = null;
            //循环遍历从 AQS 队列从后至前找到队列中最前面一个需要unpark的节点
            //注意这里做了判断t不等于null且t不等于头结点且t.waitStatus <= 0
            //也就是找到的节点必定是有效的
            for (Node t = tail; t != null && t != node; t = t.prev)
                //最后一个是有效的
                //还会继续往前找倒数第二个是不是有效
                if (t.waitStatus <= 0){
                    s = t;
                }
        }
        //唤醒头结点的下一个节点 去获取锁
        if (s != null)
            //唤醒线程
            LockSupport.unpark(s.thread);
        }
    }

isOnSyncQueue:判断是否在同步队列

    
  //默认新创建的node就是 Node.CONDITION
  final boolean isOnSyncQueue(Node node) {
        //等于-2说明在condition等待队列中 不在同步队列 返回false即可
        if (node.waitStatus == Node.CONDITION || node.prev == null)
            return false;
        //  If has successor(继任者), it must be on sync queue
        if (node.next != null) 
            return true;
        //从队列尾部开始找 找到就是 true  否则就是 false
        return findNodeFromTail(node);
    }
    
    //从队列尾部开始找 找到就是 true  否则就是 false
     private boolean findNodeFromTail(Node node) {
        Node t = tail;
        for (;;) {
            if (t == node)
                return true;
            if (t == null)
                return false;
            t = t.prev;
        }
    }

checkInterruptWhileWaiting:检查await期间是否中断

唤醒park,判断是否被打断和被打断时机

//Thread.interrupted() 返回true 说明中途被打断过
//进入判断 (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT)
//如果 transferAfterCancelledWait 返回true 说明是在signal之前被打断  返回 THROW_IE
//如果 transferAfterCancelledWait 返回false 说明是在signal之后被打断 返回 REINTERRUPT//Thread.interrupted() 返回false  说明中途没有被打断过
//checkInterruptWhileWaiting返回0/***
如果线程被打断:
但进入同步队列成功:
    THROW_IE = -1 退出await()方法需要抛出异常,这种模式对应于中断发生在signal之前。
                因为只有在signal之前才能cas将0变成-2,进入同步队列成功。
但是进入同步队列失败:
    REINTERRUPT=1 退出await()方法需要自我打断,这种模式对应于中断发生在signal之后
                因为只有在signal之后,cas将0变成-2必然失败,进入同步队列失败。
***/
private int checkInterruptWhileWaiting(Node node) {
            return Thread.interrupted() ?
                (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT)
                :
                0;
        }
​
​
​
​
​
/***
如果线程被打断:
但进入同步队列成功:
    THROW_IE = -1 退出await()方法需要抛出异常,这种模式对应于中断发生在signal之前。
                因为只有在signal之前才能cas将0变成-2,进入同步队列成功。
但是进入同步队列失败:
    REINTERRUPT=1 退出await()方法需要自我打断,这种模式对应于中断发生在signal之后
                因为只有在signal之后,cas将0变成-2必然失败,进入同步队列失败。
     对应的场景是线程A先调用了signal方法,然后当前节点被移到到了同步队列
     然后线程B调用interrupt方法对当前节点进行打断唤醒 
     也就是线程A把节点挪到了同步队列 还没执行unpark
     线程B打断了节点唤醒了线程 执行了 checkInterruptWhileWaiting
     这个时间点很短
***/
final boolean transferAfterCancelledWait(Node node) {
        //如果节点的状态使用cas由-2改为0修改成功
        //那么进入同步队列并返回true 代表进入同步队列成功
        if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
            enq(node);
            return true;
        }
        
        //如果上面的代码执行失败 返回false
        while (!isOnSyncQueue(node))
            Thread.yield();
        return false;
    }

acquireQueued:

尝试获取锁&打断模式非signal前被打断

        //前提:(线程没有被打断并且被调用了signal方法被唤醒) 或者 (是在signal之后被打断)  
        //那么就尝试去获取锁
        //如果获取不到就继续在同步队列park阻塞直到获取到锁
        //如果获取到锁,并且打断模式是在signal之后
        //interruptMode = REINTERRUPT;
        //这里无视打断模式也是不可打断的体现
        if (acquireQueued(node, savedState) && interruptMode != THROW_IE){
             interruptMode = REINTERRUPT; 

unlinkCancelledWaiters

     //断开取消节点
     private void unlinkCancelledWaiters() {
            Node t = firstWaiter;
            Node trail = null;
            while (t != null) {
                Node next = t.nextWaiter;
                
                //线程已经被取消
                static final int CANCELLED =  1;
                //线程需要去被唤醒
                static final int SIGNAL    = -1;
                //线程正在唤醒等待条件
                static final int CONDITION = -2;
                //线程的共享锁应该被无条件传播
                static final int PROPAGATE = -3;
                
                //不等于-2说明需要从等待队列移除
                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;
            }
        }

reportInterruptAfterWait

// ㈤ 应用打断模式
    private void reportInterruptAfterWait(int interruptMode)
            throws InterruptedException {
        // 打断模式 - 说明进入等待队列失败,需要自我打断
        // private static final int REINTERRUPT =  1;
        // 打断模式 - 说明进入等待队列成功,需要抛出异常
        //private static final int THROW_IE    = -1;
        if (interruptMode == THROW_IE)
            throw new InterruptedException();
        else if (interruptMode == REINTERRUPT)
            selfInterrupt();
    }
 static void selfInterrupt() {
        Thread.currentThread().interrupt();
    }

awaitNanos(long nanosTimeout)

    // 等待 - 直到被唤醒或打断或超时
   public final long awaitNanos(long nanosTimeout) throws InterruptedException {
        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
        // 添加一个 Node 至等待队列, 见 ㈠
        Node node = addConditionWaiter();
        // 释放节点持有的锁
        int savedState = fullyRelease(node);
        // 获得最后期限
        final long deadline = System.nanoTime() + nanosTimeout;
        int interruptMode = 0;
        // 如果该节点还没有转移至 AQS 队列, 阻塞
        while (!isOnSyncQueue(node)) {
        // 已超时, 退出等待队列
            if (nanosTimeout <= 0L) {
                transferAfterCancelledWait(node);
                break;
            }
            // park 阻塞一定时间, spinForTimeoutThreshold 为 1000 ns
            if (nanosTimeout >= spinForTimeoutThreshold)
                LockSupport.parkNanos(this, nanosTimeout);
            // 如果被打断, 退出等待队列
            if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                break;
            nanosTimeout = deadline - System.nanoTime();
        }
        // 退出等待队列后, 还需要获得 AQS 队列的锁
        if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
            interruptMode = REINTERRUPT;
        // 所有已取消的 Node 从队列链表删除, 见 ㈡
        if (node.nextWaiter != null)
            unlinkCancelledWaiters();
        // 应用打断模式, 见 ㈤
        if (interruptMode != 0)
            reportInterruptAfterWait(interruptMode);
        return deadline - System.nanoTime();
    }
    // 等待 - 直到被唤醒或打断或超时, 逻辑类似于 awaitNanos
    public final boolean awaitUntil(Date deadline) throws InterruptedException {
        // ...
    }
    // 等待 - 直到被唤醒或打断或超时, 逻辑类似于 awaitNanos
    public final boolean await(long time, TimeUnit unit) throws InterruptedException {
        // ...
    }
    // 工具方法 省略 ...

1.进入await队列

2.释放锁

3.唤醒同步队列的头节点的下一个节点。如果头结点的下一个节点不为空且没有取消,unpark该节点。

否则从尾节点开始找,从后往前找最前面一个是-1状态的节点。

signal源码

     // 唤醒 - 必须持有锁才能唤醒, 因此 doSignal 内无需考虑加锁
    public final void signal() {
         //判断当前线程是否是持有锁的线程 不是就报错,这也解释了为什么调用signal为什么要持有锁
         if (!isHeldExclusively())
             throw new IllegalMonitorStateException();
        //获取头结点
         Node first = firstWaiter;
         if (first != null){
             //唤醒
             doSignal(first);
         }
     }
​
​
    // 唤醒 - 将没取消的第一个节点转移至AQS同步队列
    private void doSignal(Node first) {
        //first是头结点firstWaiter
        do {
            // 如果头结点下一个节点是null 说明目前只有1个节点
            // 将尾节点置为null
            //firstWaiter是first的下一个节点
            if ( (firstWaiter = first.nextWaiter) == null) {
                lastWaiter = null;
            }
            //
            //断开头结点的下一个节点 即 排在第二的节点
            first.nextWaiter = null;
            //将等待队列中的 Node 转移至 AQS 队列, 
            //如果转移至 AQS 队列失败且还有节点则继续向下循环 ㈢
            //每次只会从等待队列移动一个节点到同步队列
            //因为transferForSignal返回true代表转移成功
            //first = firstWaiter 将first的下一个节点赋值给first
        } while (!transferForSignal(first) &&(first = firstWaiter) != null);
    }
    
    // 外部类方法, 方便阅读, 放在此处
    // ㈢ 如果节点状态是取消, 返回 false 表示转移失败, 否则转移成功
    final boolean transferForSignal(Node node) {
        //node是头结点
        // 如果状态已经不是 Node.CONDITION=-2, 说明被取消了
        // 同时这里
        // 和await方法中addConditionWaiter方法设置为Node.CONDITION呼应
        // 和checkInterruptWhileWaiting判断打断时机的代码呼应 因为cas -2 改为 0 只能有1个地方成功
         if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
            return false;
        // 将等待队列头结点加入同步队列尾部
        Node p = enq(node);
        // 上一个节点被取消 或者 上一个节点 设置状态为 Node.SIGNAL=-1 失败
        int ws = p.waitStatus;
    /***
    下面的代码是为了进一步提升性能,针对两种情况:
    如果插入node前,AQS内部等待队列的队尾节点就已经被取消,则满足wc > 0
    如果插入node后,AQS内部等待队列的队尾节点已经稳定,满足tail.waitStatus == 0
    但在执行ws > 0之后!compareAndSetWaitStatus(p, ws, Node.SIGNAL)之前被取消,则CAS也会失败,满足compareAndSetWaitStatus(p, ws, Node.SIGNAL) == false
    这两种情况下,提前唤醒node能够在等待锁的同时,预先完成一部分ConditionObject#await()中无需同步的工作。这部分成本不能被轻易忽视,因为条件队列被应用最多的场景是高并发,大量线程累加起来的成本是很可观的。
​
    链接:https://www.jianshu.com/p/a932c184db52
    ***/
        节点被取消的原因:
        This node is cancelled due to timeout or interrupt.
        Nodes never leave this state. In particular,
        a thread with cancelled node never again blocks.
        //如果上一个节点被取消,或者在执行ws > 0之后
        //!compareAndSetWaitStatus(p, ws, Node.SIGNAL)之前
        //被取消那么就unpark当前节点的上一个节点
        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) {
            // unpark 取消阻塞, 让线程重新同步状态
            LockSupport.unpark(node.thread);
        }
        return true;
    }
    
​
// 全部唤醒 - 等待队列的所有节点转移至 AQS 队列
    private void doSignalAll(Node first) {
        lastWaiter = firstWaiter = null;
        do {
            Node next = first.nextWaiter;
            first.nextWaiter = null;
            transferForSignal(first);
            first = next;
        } while (first != null);
    } 
   
    // 全部唤醒 - 必须持有锁才能唤醒, 因此 doSignalAll 内无需考虑加锁
    public final void signalAll() {
        if (!isHeldExclusively())
            throw new IllegalMonitorStateException();
        Node first = firstWaiter;
        if (first != null)
            doSignalAll(first);
    }
    // 不可打断等待 - 直到被唤醒
    public final void awaitUninterruptibly() {
    // 添加一个 Node 至等待队列, 见 ㈠
        Node node = addConditionWaiter();
    // 释放节点持有的锁, 见 ㈣
        int savedState = fullyRelease(node);
        boolean interrupted = false;
    // 如果该节点还没有转移至同步队列, 阻塞
        while (!isOnSyncQueue(node)) {
            // park 阻塞
            LockSupport.park(this);
        // 如果被打断, 仅设置打断状态
            if (Thread.interrupted()){
                interrupted = true;
            }                
        }
        // 唤醒后, 尝试竞争锁, 如果失败进入 AQS 队列
        if (acquireQueued(node, savedState) || interrupted)
            selfInterrupt();
    }
​
    // ㈠ 添加一个 Node 至等待队列
    private Node addConditionWaiter() {
        Node t = lastWaiter;
        //Node.CONDITION=-2 表示结点等待在Condition上,!= Node.CONDITION代表结点没有在等待队列上
        //所有已取消的 Node 从队列链表断开, 见 ㈡
        if (t != null && t.waitStatus != Node.CONDITION) {
            unlinkCancelledWaiters();
            t = lastWaiter;
        }
        // 创建一个关联当前线程的新Node, 
        //如果头部为空,那么添加至队列头部,头部尾部都指向这个新node
        //如果头部不为空,那么添加到队列尾部
        Node node = new Node(Thread.currentThread(), Node.CONDITION);
        if (t == null)
            firstWaiter = node;
        else
            t.nextWaiter = node;
        lastWaiter = node;
        return node;
    }
​
​
    // ㈣ 因为某线程可能重入,需要将 state 全部释放
    final int fullyRelease(Node node) {
        //此处的节点是要await的节点
        boolean failed = true;
        try {
            //注意这里释放的是多次加锁累加的state
            int savedState = getState();
            if (release(savedState)) {
                failed = false;
                return savedState;
            } else {
                throw new IllegalMonitorStateException();
            }
        } finally {
            if (failed)
                node.waitStatus = Node.CANCELLED;
        }
    }
​
}