Condition 原理剖析

302 阅读1分钟

一、await 释放锁并阻塞

image.png

会首先判断线程是否是中断状态,如果是中断状态的话,会抛出异常,然后将当前线程封装为 Node 节点此时 Node 节点的状态为 CONDITION ,并通过 nextWaiter 指针构成单向链表,入队完成之后,就尝试将自身所持有的锁释放,锁释放完毕后,会判断自身是否在 AQS 同步队列中,如果不在的话,就会通过 park 将自身挂起。

当后续被 signal 唤醒之后,会走 acquireQueued 这个方法,主要就是 ReentrantLock 里尝试获取锁的地方,如果获取失败的话,会将自身进行挂起,等待别的线程执行 unlock 将其唤醒。

condition#await (2).png

二、signal 唤醒线程

image.png

调用 Signal 唤醒线程的时候,会先判断是不是锁拥有者,如果不是的话会直接抛出异常,然后获取到 Condition 队列中的头结点,这时会判断头结点是否有下一个节点,如果没有的话,就将尾节点设置为 null ,如果有的话,会将头结点的 next 属性设置为 null ,相当于一个出队的操作。

之后通过 CAS 将节点状态从 Condition 设置为 0 ,然后执行入队操作,这里的入队指的是 加入 AQS 队列中,并设置 waitStatus 为 SIGNAL 状态 ,然后返回 true ,后续线程唤醒的功能,就是走 AQS 的逻辑,也就是别的线程 unlock 释放锁之后,会从 CAS 队列中获取头结点的下一个节点,进行 unpark 唤醒线程。

condition#signal.png