为啥在 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 之前运行?