再看await方法
线程被唤醒后执行流程:
- 唤醒后,要先确认是signal唤醒还是中断唤醒,还是signal唤醒后被中断
- 确保当前线程的node已经在AQS链表中
- 执行acquireQueued方法,等待获取锁资源
- 在获取锁资源后,要确认是否在获取锁资源过程中被中断过;如果中断过,并且不是THROW_IE,那就确保interruptMode是REINTERRUPT
- 确认当前node已经不在条件队列中了
- 最终根据interruptMode来决定具体要做的事情
- 0:什么也不用做
- THROW_IE:抛出异常
- REINTERRUPT:执行interrupt方法
public final void await() throws InterruptedException {
// 如果线程中断,则抛出中断异常
if (Thread.interrupted())
throw new InterruptedException();
// 将当前线程加入到条件队列中
Node node = addConditionWaiter();
// 释放所有锁资源,并且保留重入的次数
int savedState = fullyRelease(node);
// interruptMode表示唤醒模式
int interruptMode = 0;
// 如果线程不在同步队列中,则挂起。
// 有这样一种情况,线程在执行完fullyRelease方法后,时间片用完了,另一个线程拿到锁资源
// 并且另一个线程调用了signal方法,signal方法会将当前线程从条件队列中转移到同步队列中
// 此时,如果当前线程获得cpu资源继续执行,是不需要执行LockSupport.park(this)方法的
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
// 走到这里,说明当前线程被唤醒
// 第一种情况:被signal方法唤醒,节点一定被放到同步队列中
// 第二种情况:被同步队列中前一个节点唤醒,节点一定被放到同步队列中
// 第三种情况:被中断唤醒,节点还没有放到同步队列中
// 第四种情况:被中断唤醒,节点已经放到同步队列中
// 对于第三种情况,会在执行checkInterruptWhileWaiting方法时,将节点放到同步队列中
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
// 线程走到这里,节点必定已经放到同步队列中了
// acquireQueued方法只有在线程获取到锁后才会返回
// acquireQueued方法中线程被唤醒去竞争锁资源有两种情况
// 一种是被同步队列前一个节点唤醒,另一种是被中断唤醒
// 如果是被中断唤醒,可能后续有业务要处理这个中断
// 但是acquireQueued方法中的parkAndCheckInterrupt方法
// 将线程中断标志位设置成false了,这是不合理的
// 所以,如果线程被中断唤醒,acquireQueued方法会返回true
// 这样在reportInterruptAfterWait方法中会将中断标志位设置成true
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
// 进入这里说明线程是先被移动到同步队列中,然后被中断
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
// 当前线程被中断唤醒,当前node还在条件队列中,需要脱离条件队列
unlinkCancelledWaiters();
// 如果interrupteMode是0,说明线程在signal后以及持有锁过程中,没有被中断过,什么事也不用做
if (interruptMode != 0)
// interruptMode是THROW_IE:抛出异常
// interruptMode是REINTERRUPT:执行线程interrupt方法
// 需要注意的是,当await方法抛出中断异常时,线程是已经持有锁的
// 所以最好在捕获异常后将锁资源释放掉
reportInterruptAfterWait(interruptMode);
}
private int checkInterruptWhileWaiting(Node node) {
// 如果线程没有被中断,返回0
// 如果线程在移动到同步队列前发生中断,返回THROW_IE,值为-1
// 如果线程在移动到同步队列后发生中断,返回REINTERRUPT,值为1
return Thread.interrupted() ?
(transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
0;
}
final boolean transferAfterCancelledWait(Node node) {
if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
// 进入这里说明线程在移动到同步队列前发生中断
// 此时节点的状态还是CONDITION,可以通过CAS改成0
// 将node添加到AQS节点,此时条件队列和同步队列中都有此节点了
// 不过在await方法的unlinkCancelledWaiters方法中会将此节点从条件队列中删除
enq(node);
return true;
}
// 进入这里说明线程在移动到同步队列后发生中断
// 判断同步队列中是否有此节点(其实没有必要)
// 如果没有等待节点放入同步队列中
while (!isOnSyncQueue(node))
Thread.yield();
return false;
}
// 删除掉condition链表中waitStatus值不为-2的节点
private void unlinkCancelledWaiters() {
Node t = firstWaiter;
Node trail = null;
while (t != null) {
Node next = t.nextWaiter;
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;
}
}
private void reportInterruptAfterWait(int interruptMode)
throws InterruptedException {
if (interruptMode == THROW_IE)
throw new InterruptedException();
else if (interruptMode == REINTERRUPT)
// Thread.currentThread().interrupt();
selfInterrupt();
}