并发条件队列之Condition 精讲 (5)

       此情况就是已经被唤醒了那么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(); }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wssfjf.html