一、await 释放锁并阻塞
会首先判断线程是否是中断状态,如果是中断状态的话,会抛出异常,然后将当前线程封装为 Node 节点此时 Node 节点的状态为 CONDITION ,并通过 nextWaiter 指针构成单向链表,入队完成之后,就尝试将自身所持有的锁释放,锁释放完毕后,会判断自身是否在 AQS 同步队列中,如果不在的话,就会通过 park 将自身挂起。
当后续被 signal 唤醒之后,会走 acquireQueued 这个方法,主要就是 ReentrantLock 里尝试获取锁的地方,如果获取失败的话,会将自身进行挂起,等待别的线程执行 unlock 将其唤醒。
二、signal 唤醒线程
调用 Signal 唤醒线程的时候,会先判断是不是锁拥有者,如果不是的话会直接抛出异常,然后获取到 Condition 队列中的头结点,这时会判断头结点是否有下一个节点,如果没有的话,就将尾节点设置为 null ,如果有的话,会将头结点的 next 属性设置为 null ,相当于一个出队的操作。
之后通过 CAS 将节点状态从 Condition 设置为 0 ,然后执行入队操作,这里的入队指的是 加入 AQS 队列中,并设置 waitStatus 为 SIGNAL 状态 ,然后返回 true ,后续线程唤醒的功能,就是走 AQS 的逻辑,也就是别的线程 unlock 释放锁之后,会从 CAS 队列中获取头结点的下一个节点,进行 unpark 唤醒线程。