为什么要在Catch InterruptException块中调用Thread.CurrentThread.Interrupt()?

为什么要在CATCH块中调用ABC_0_方法?

70788 次浏览

这样做是为了保持状态

当您捕捉到InterruptedException并将其吞下时,您实际上阻止了任何高级方法/线程组注意到该中断。这可能会导致问题。

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

实践中的Java并发第7.1.3章:中断响应中对此进行了更详细的讨论。它的规则是:

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

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

Thread.currentThread.interrupt()并且不引发任何其他异常或以任何其他方式发出中断请求(例如,在线程的主循环中设置interrupted局部变量)的唯一理由是您确实无法对异常执行任何操作的情况,如在finally块中。

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

注意:

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

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

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

Thread.currentThread().interrupt();

这可以确保线程能够尽快重新引发InterruptedException.

我认为这个代码示例让事情变得更清楚了。 执行此工作的类:

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();
}
}

尝试调用中断而不将状态设置回来。

参考Java文档

如果该线程在wait()、join() 睡眠(长),则其中断状态将被清除,并且它将 接收InterruptedException.

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

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

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

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

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