深入理解 JUC:AQS 队列同步器( 四 )

等待:await下面来分析一下 ConditionObject 类针对 Condition 接口方法的实现 , 首先来看一下 ConditionObject#await 方法 , 该方法用于将当前线程添加到条件队列中进行等待 , 同时支持响应中断 。 方法实现如下:
public final void await() throws InterruptedException {if (Thread.interrupted()) {// 立即响应中断throw new InterruptedException();}// 将当前线程添加到等待队列末尾 , 等待状态为 CONDITIONNode node = this.addConditionWaiter();// 释放当前线程持有的资源int savedState = fullyRelease(node);int interruptMode = 0;while (!isOnSyncQueue(node)) { // 如果当前结点位于条件队列中 , 则循环// 阻塞当前线程LockSupport.park(this);// 如果线程在阻塞期间被中断 , 则退出循环if ((interruptMode = this.checkInterruptWhileWaiting(node)) != 0) {break;}}// 如果在同步队列中等待期间被中断 , 且之前的中断状态不为 THROW_IEif (acquireQueued(node, savedState)}if (node.nextWaiter != null) {// 清除条件队列中所有状态不为 CONDITION 的结点this.unlinkCancelledWaiters();}// 如果等待期间被中断 , 则响应中断if (interruptMode != 0) {this.reportInterruptAfterWait(interruptMode);}}因为 ConditionObject#await 方法支持响应中断 , 所以在方法一开始会先检查一下当前线程是否被中断 , 如果是则抛出 InterruptedException 异常 , 否则继续将当前线程加入到条件队列中进行等待 。 整体执行流程可以概括为:

  1. 将当前线程加入到条件队列末端 , 并设置等待状态为 CONDITION;
  2. 释放当前线程所持有的资源 , 避免饥饿或死锁;
  3. 基于自旋机制在条件队列中等待 , 直到被其它线程转移到同步队列 , 或者等待期间被中断;
  4. 如果等待期间被中断 , 则响应中断 。
ConditionObject 定义了两种中断响应方式 , 即:REINTERRUPT 和 THROW_IE 。 如果是 REINTERRUPT , 则线程会调用 Thread#interrupt 方法中断自己;如果是 THROW_IE , 则线程会直接抛出 InterruptedException 异常 。
下面继续分析一下支撑 ConditionObject#await 运行的其它几个方法 , 包括 addConditionWaiter、fullyRelease、isOnSyncQueue , 以及 unlinkCancelledWaiters 。
方法 ConditionObject#addConditionWaiter 用于将当前线程包装成 Node 结点对象添加到条件队列的末端 , 期间会执行清除条件队列中处于取消状态(等待状态不为 CONDITION)的线程结点 。 方法实现如下:
private Node addConditionWaiter() {// 获取条件队列的末尾结点Node t = lastWaiter;// 如果末尾结点状态不为 CONDITION , 表示对应的线程已经取消了等待 , 需要执行清理操作if (t != nullt = lastWaiter;}// 构建当前线程对应的 Node 结点 , 等待状态为 CONDITION , 并添加到条件队列末尾Node node = new Node(Thread.currentThread(), Node.CONDITION);if (t == null) {firstWaiter = node;} else {t.nextWaiter = node;}lastWaiter = node;return node;}将当前线程对象添加到条件队列中的过程本质上是一个简单的链表插入操作 , 在执行插入操作之前 , 上述方法会先对条件队列执行一遍清理操作 , 清除那些状态不为 CONDITION 的结点 。 具体实现位于 ConditionObject#unlinkCancelledWaiters 方法中:
private void unlinkCancelledWaiters() {Node t = firstWaiter;Node trail = null; // 记录上一个不被删除的结点while (t != null) {Node next = t.nextWaiter;// 如果结点上的线程等待状态不为 CONDITION , 则删除对应结点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;}}


推荐阅读