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 如何处理中断的主要内容,如果未能解决你的问题,请参考以下文章

AVPlayer : 如何处理网络中断

如何处理瞬态类加载错误,例如线程中断

Linux内核17-硬件如何处理中断和异常

JAVA多线程之中断机制(如何处理中断?)

如何处理网络中断和连接池

JAVA多线程之中断机制(如何处理中断?)