此情况就是已经被唤醒了那么isOnSyncQueue(node)返回true,在同步队列中了就,退出了while循环。
退出while循环后接下来还是利用acquireQueued争锁,因为前面没有发生中断,则interruptMode=0,这时,如果在争锁的过程中发生了中断,则acquireQueued将返回true,则此时interruptMode将变为REINTERRUPT。
接下是判断node.nextWaiter != null,由于在调用signal方法时已经将节点移出了队列,所有这个条件也不成立。
最后就是汇报中断状态了,此时interruptMode的值为REINTERRUPT,说明线程在被signal后又发生了中断,这个中断发生在抢锁的过程中,这个中断来的太晚了,因此我们只是再次自我中断一下。
情况二中的第二种情况总结:
线程被signal方法唤醒,此时并没有发生过中断
因为没有发生过中断,我们将从checkInterruptWhileWaiting处返回,此时interruptMode=0
接下来我们回到while循环中,因为signal方法保证了将节点添加到同步队列中,此时while循环条件不成立,循环退出
接下来线程将在同步队列中以阻塞的方式获取,如果获取不到锁,将会被再次挂起
线程获取到锁返回后,我们检测到在获取锁的过程中发生过中断,并且此时interruptMode=0,这时,我们将interruptMode修改为REINTERRUPT
最后我们通过reportInterruptAfterWait将当前线程再次中断,但是不会抛出InterruptedException
3.情况三一直没发生中断
直接正常返回
await方法总结
进入await()时必须是已经持有了锁
离开await()时同样必须是已经持有了锁
调用await()会使得当前线程被封装成Node扔进条件队列,然后释放所持有的锁
释放锁后,当前线程将在条件队列中被挂起,等待signal或者中断
线程被唤醒后会将会离开条件队列进入同步队列中进行抢锁
若在线程抢到锁之前发生过中断,则根据中断发生在signal之前还是之后记录中断模式
线程在抢到锁后进行善后工作(离开条件队列,处理中断异常)
线程已经持有了锁,从await()方法返回
在这一过程中我们尤其要关注中断,如前面所说,中断和signal所起到的作用都是将线程从条件队列中移除,加入到同步队列中去争锁,所不同的是,signal方法被认为是正常唤醒线程,中断方法被认为是非正常唤醒线程,如果中断发生在signal之前,则我们在最终返回时,应当抛出InterruptedException;如果中断发生在signal之后,我们就认为线程本身已经被正常唤醒了,这个中断来的太晚了,我们直接忽略它,并在await()返回时再自我中断一下,这种做法相当于将中断推迟至await()返回时再发生。 2. awaitUninterruptibly public final void awaitUninterruptibly() { Node node = addConditionWaiter(); int savedState = fullyRelease(node); boolean interrupted = false; while (!isOnSyncQueue(node)) { LockSupport.park(this); if (Thread.interrupted()) // 发生了中断后线程依旧留在了条件队列中,将会再次被挂起 interrupted = true; } if (acquireQueued(node, savedState) || interrupted) selfInterrupt(); }