为啥在 catch InterruptException 块中调用 Thread.currentThread.interrupt()?

Posted

技术标签:

【中文标题】为啥在 catch InterruptException 块中调用 Thread.currentThread.interrupt()?【英文标题】:Why invoke Thread.currentThread.interrupt() in a catch InterruptException block?为什么在 catch InterruptException 块中调用 Thread.currentThread.interrupt()? 【发布时间】:2011-06-21 20:44:43 【问题描述】:

为什么要在 catch 块中调用 Thread.currentThread.interrupt() 方法?

【问题讨论】:

【参考方案1】:

这样做是为了保持状态

当您捕获InterruptedException 并吞下它时,您基本上可以防止任何更高级别的方法/线程组注意到中断。这可能会导致问题。

通过调用Thread.currentThread().interrupt(),您设置了线程的中断标志,因此更高级别的中断处理程序会注意到它并可以适当地处理它。

Java Concurrency in Practice 在第 7.1.3 章:响应中断中更详细地讨论了这一点。它的规则是:

只有实现线程中断策略的代码才能吞下中断请求。通用任务和库代码不应吞下中断请求。

【讨论】:

在documentation 中声明“按照惯例,任何通过抛出InterruptedException 退出的方法在这样做时都会清除中断状态 我认为这使得为什么您需要保留中断状态的答案更加清晰。 还值得注意的是,一旦您通过其他“传递机制”(@ 987654327@ 并希望或不能重新抛出它。 higher-level methods/thread groups 是什么意思?【参考方案2】:

我认为这个代码示例让事情变得更清楚了。 完成这项工作的班级:

public class InterruptedSleepingRunner implements Runnable 
    @Override
    public void run() 
        doAPseudoHeavyWeightJob();
    

    private void doAPseudoHeavyWeightJob() 
        for (int i = 0; i < Integer.MAX_VALUE; i++) 
            // You are kidding me
            System.out.println(i + " " + i * 2);
            // Let me sleep <evil grin>
            if (Thread.currentThread().isInterrupted()) 
                System.out.println("Thread interrupted\n Exiting...");
                break;
             else 
                sleepBabySleep();
            
        
    

    protected void sleepBabySleep() 
        try 
            Thread.sleep(1000);
         catch (InterruptedException e) 
            Thread.currentThread().interrupt();
        
    

Main 类:

public class InterruptedSleepingThreadMain 
    public static void main(String[] args) throws InterruptedException 
        Thread thread = new Thread(new InterruptedSleepingRunner());
        thread.start();
        // Giving 10 seconds to finish the job.
        Thread.sleep(10000);
        // Let me interrupt
        thread.interrupt();
    

尝试在不设置状态的情况下调用中断。

【讨论】:

所以结论是?? 谢谢。我明白你现在的意思了:repl.it/@djangofan/InterruptedThreadExample 我认为他的意思是Thread.currentThread().interrupt(); 允许您更快地退出线程,因此当InterruptedException e 被捕获时,线程会在那里停止。而如果不使用Thread.currentThread().interrupt();,线程会继续执行..【参考方案3】:

注意:

http://download.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

如何停止长时间等待(例如,等待输入)的线程?

要使这项技术发挥作用,任何捕获中断异常但不准备处理它的方法都必须立即重新声明异常。我们说重新断言而不是重新抛出,因为并不总是可以重新抛出异常。 如果捕获 InterruptedException 的方法未声明抛出此(已检查)异常,则应使用以下咒语“重新中断自身”:

Thread.currentThread().interrupt();

这确保线程将尽快重新引发 InterruptedException。

【讨论】:

【参考方案4】:

我认为这是一种不好的做法,或者至少有点冒险。 通常更高级别的方法不执行阻塞操作,他们永远不会在那里看到InterruptedException。如果你在每一个你执行可中断操作的地方都屏蔽它,你永远不会得到它。

Thread.currentThread.interrupt() 的唯一理由是你真的什么都做不了除了finally 块中的例外情况。

如果您想更好地了解 Thread.currentThread.interrupt() 调用的含义,请参阅 Péter Török 的回答。

【讨论】:

【参考方案5】:

参考java文档

如果该线程在调用 wait()、join() 时被阻塞, sleep(long),则其中断状态将被清除,它会 收到一个 InterruptedException。

如果该线程在 I/O 操作中被阻塞,则该线程的中断 状态将被设置,线程将收到一个 ClosedByInterruptException。

如果该线程在 Selector 中被阻塞,则该线程的中断 状态将被设置,它将立即从选择中返回 操作。

如果前面的条件都不成立,那么这个线程的中断 状态将被设置。

因此,如果您将@Ajay George Answer 中的 sleepBabySleep() 方法更改为 I/O 操作或只是一个 sysout,则无需将状态设置回停止程序。 (顺便说一句,他们甚至不抛出 InterruptedException)

就像@Péter Török 所说 => 这样做是为了保持状态。 (特别是对于会抛出 InterruptedException 的方法)

【讨论】:

以上是关于为啥在 catch InterruptException 块中调用 Thread.currentThread.interrupt()?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 NSOperation 示例代码使用@try & @catch

为啥 try..catch..finally 块的 finally 节在 catch 之前运行?

为啥我必须使用 try/catch [重复]

为啥 axios .catch() 在 redux 中间件中捕获 javascript 错误?

为啥 .catch() 没有做任何事情?

为啥我们在 Flutter/Dart 中的 catch 参数中加上“e”?