AQS 如何处理中断
Posted
技术标签:
【中文标题】AQS 如何处理中断【英文标题】:How does AQS handle interrupts 【发布时间】:2021-12-27 16:00:44 【问题描述】:当一个节点在排队等待锁时,另一个线程中断了他,他会旋转一次然后取消中断并重新挂起自己,就像它从未中断过一样。
按照我的理解,他应该取消锁获取,但现在看来不是这样。当他之前的节点释放锁时,他仍然会像从未中断过一样抢锁,谁能告诉我为什么? 版本是JDK8
final boolean acquireQueued(final Node node, int arg)
boolean failed = true;
try
boolean interrupted = false;
for (;;)
final Node p = node.predecessor();
if (p == head && tryAcquire(arg))
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
finally
if (failed)
cancelAcquire(node);
private final boolean parkAndCheckInterrupt()
LockSupport.park(this);
return Thread.interrupted();
【问题讨论】:
嗨,欢迎来到 ***。您能否重新表述您的问题,可能会提供更多上下文信息?我无法理解您到底在问什么。 感谢您的回答。我的问题是,当Thread从block中被唤醒时,使用thread.interrupted()清除中断状态,如果没有获得锁,则Thread再次挂起。按照我的理解应该进入cancelAcquire方法,但是我没有找到入口,你能明白我的意思吗?对不起,我的英语不太好 【参考方案1】:在您的代码中,线程只能以一种方式离开无限 for(;;)
循环 - 在它满足 if(p == head && tryAcquire(arg))
的条件之后 - 因为它是唯一的 return
语句,所以您也没有任何中断。
但是,您说“没有获得锁”,这意味着线程必须继续执行这个for循环中的内容,这意味着执行第二个if(再次挂起线程)。
当你有一个构造时
try
// some code
finally
// finally execution
finally
块中的代码只有在执行离开try
块后才会执行(正常或由于异常)。
【讨论】:
是的,所以当一个线程被中断时,根据AbstractQueuedSynchronizer的来源,他会再次尝试获取锁,然后继续挂起,所以他无法进入cancelAcquire方法,然后如何取消获取锁?中断的意思是取消锁的获取,但是看源码会继续获取锁,直到成功,然后进入finally方法,不会执行cancelAcquire。这就是我感到困惑的地方。 再次感谢您的回答。我觉得我明白了。对于独占锁,Doug Lea 提供了三种获取方式,“acquireQueued,doAcquireInterruptibly,doAcquireNanos”,其中两种支持中断,我问的方法不支持中断,作者在注释中也说了,“以独占不间断模式获取已在队列中的线程。由条件等待方法和获取使用。”。所以,他不赞成打断。 finally 方法是出于谨慎添加的。但是,cancelAcquire 方法几乎从不进入。以上是关于AQS 如何处理中断的主要内容,如果未能解决你的问题,请参考以下文章