以下处理 InterruptedException
的方式有何区别?最佳方式是什么?
try{
//...
} catch(InterruptedException e) {
Thread.currentThread().interrupt();
}
或
try{
//...
} catch(InterruptedException e) {
throw new RuntimeException(e);
}
编辑:我还想知道在什么情况下使用这两个。
以下处理 InterruptedException
的方式有何区别?最佳方式是什么?
try{
//...
} catch(InterruptedException e) {
Thread.currentThread().interrupt();
}
或
try{
//...
} catch(InterruptedException e) {
throw new RuntimeException(e);
}
编辑:我还想知道在什么情况下使用这两个。
If yes, then throws InterruptedException
should be part of your method signature, and you should let the exception propagate (i.e. don't catch it at all).
Example: Your method waits for a value from the network to finish the computation and return a result. If the blocking network call throws an
InterruptedException
your method can not finish computation in a normal way. You let theInterruptedException
propagate.
int computeSum(Server server) throws InterruptedException { // Any InterruptedException thrown below is propagated int a = server.getValueA(); int b = server.getValueB(); return a + b; }
If no, then you should not declare your method with throws InterruptedException
and you should (must!) catch the exception. Now two things are important to keep in mind in this situation:
Someone interrupted your thread. That someone is probably eager to cancel the operation, terminate the program gracefully, or whatever. You should be polite to that someone and return from your method without further ado.
Even though your method can manage to produce a sensible return value in case of an InterruptedException
the fact that the thread has been interrupted may still be of importance. In particular, the code that calls your method may be interested in whether an interruption occurred during execution of your method. You should therefore log the fact an interruption took place by setting the interrupted flag: Thread.currentThread().interrupt()
Example: The user has asked to print a sum of two values. Printing "
Failed to compute sum
" is acceptable if the sum can't be computed (and much better than letting the program crash with a stack trace due to anInterruptedException
). In other words, it does not make sense to declare this method withthrows InterruptedException
.
void printSum(Server server) { try { int sum = computeSum(server); System.out.println("Sum: " + sum); } catch (InterruptedException e) { Thread.currentThread().interrupt(); // set interrupt flag System.out.println("Failed to compute sum"); } }
throw new RuntimeException(e)
是一个坏主意。这不太客气。你可以发明一个新的运行时异常,但是根本原因(有人想要停止线程的执行)可能会丢失。Runnable
: 你可能已经发现了,Runnable.run
的签名不允许重新抛出InterruptedExceptions
。那么,作为实现Runnable
的人,这意味着你需要处理可能发生的InterruptedExceptions
。要么选择一个不同的接口,比如Callable
,要么按照上面的第二种方法去做。
Calling
Thread.sleep
: You're attempting to read a file and the spec says you should try 10 times with 1 second in between. You callThread.sleep(1000)
. So, you need to deal withInterruptedException
. For a method such astryToReadFile
it makes perfect sense to say, "If I'm interrupted, I can't complete my action of trying to read the file". In other words, it makes perfect sense for the method to throwInterruptedExceptions
.
String tryToReadFile(File f) throws InterruptedException { for (int i = 0; i < 10; i++) { if (f.exists()) return readFile(f); Thread.sleep(1000); } return null; }
这篇文章已经被重写为这里的一篇文章。
interrupt()
时需要保留中断状态。不在Thread.sleep()
上这样做的原因是什么? - oksaytInterruptedException
捕获块中调用Thread.currentThread.interrupt()
将仅设置中断标志。它不会导致在外部InterruptedException
捕获块中抛出/捕获另一个InterruptedException
。 - aioobeThread.currentThread().interrupt()
,请注意线程是否具有运行循环,该循环_不_检查/清除该标志。您可能需要添加一些代码来调用/检查Thread.interrupted()
在顶层/循环中,以避免永久停留在中断状态。(例如,如果您有一个仅有一个地方捕获InterruptedException
的循环,并且您的catch块调用Thread.currentThread.interrupt()
,则如果没有从上一个调用中清除它,则随后的该代码调用将立即重新触发该异常。 - Mr Weasel恰好今天早上在去上班的路上,我正在阅读Brian Goetz的Java并发实践,其中提到了这个问题。基本上他说你应该做以下三件事之一:
传播InterruptedException - 声明您的方法抛出已检查的InterruptedException
,以便调用者必须处理它。
恢复中断 - 有时您无法抛出InterruptedException
。在这种情况下,您应该捕获InterruptedException
并通过在currentThread
上调用interrupt()
方法来恢复中断状态,以便调用堆栈中更高层次的代码可以看到发生了中断,并快速从方法返回。注意:仅当您的方法具有“尝试”或“最佳努力”语义时,即如果该方法未能完成其目标,则不会发生任何关键事件。例如,log()
或sendMetric()
可能是这样的方法,或者boolean tryTransferMoney()
,但不是void transferMoney()
。有关更多详细信息,请参见here。
Uninterruptibles
。 Uninterruptibles
接管类似于JCIP § 7.1.3中的Noncancelable Task示例中的样板代码。您想做什么?
InterruptedException
是在一个线程等待或休眠时,另一个线程使用 Thread
类中的 interrupt
方法中断它时抛出的异常。因此,如果捕获到此异常,表示该线程已被中断。通常情况下,除非您想从其他地方检查线程的“中断”状态,否则没有必要再次调用 Thread.currentThread().interrupt()
。
关于您另一种选项——抛出 RuntimeException
,这似乎不是一个很明智的做法(谁来捕获它?如何处理它?),但如果没有更多的信息,就很难说了。
Thread.currentThread().interrupt()
会重新设置中断标志,确保在更高层次上能够注意到并处理这个中断是非常有用的。请注意,这不会改变原始意思,只是使其更易于理解。 - Péter Török正确的默认选择是将InterruptedException添加到抛出列表中。中断表示另一个线程希望结束你的线程。这个请求的原因没有明确说明,完全取决于上下文,因此如果你没有任何额外的知识,应该假设它只是一种友好的关闭,而任何避免这种关闭的行为都是不友好的响应。
Java不会随机抛出InterruptedException,所有建议都不会影响你的应用程序,但我遇到过一个开发人员遵循“吞掉”策略非常不方便的情况。一个团队开发了一组大量使用Thread.Sleep的测试。现在我们开始在我们的CI服务器上运行测试,有时由于代码缺陷会陷入永久等待状态。更糟糕的是,在尝试取消CI作业时,它永远不会关闭,因为Thread.Interrupt打算中断测试而没有中断作业。我们不得不登录到计算机并手动杀死进程。
长话短说,如果你简单地抛出InterruptedException,那么你就符合了你的线程应该结束的默认意图。如果你不能将InterruptedException添加到你的抛出列表中,我会将它包装在RuntimeException中。
有一个非常合理的论点可以认为InterruptedException本身应该是一个RuntimeException,因为这将鼓励更好的“默认”处理。它不是一个RuntimeException,仅仅因为设计者坚持一条分类规则,即RuntimeException应该表示你的代码中的错误。由于InterruptedException并不直接起源于你的代码中的错误,所以它不是RuntimeException。但现实情况是,中断通常会出现,因为你的代码存在错误(例如无限循环、死锁),而Interrupt是其他线程处理该错误的方法。
如果你知道有理性的清理工作要做,那么就去做吧。如果你知道中断的更深层次原因,你可以进行更全面的处理。
因此,总结一下,你处理的选择应该遵循以下列表:
Thread.currentThread().interrupt()
作为“默认处理机制”可能非常危险,会导致意外的忙等待,因此它只被正确地提到作为最后的选择,当你知道自己在做什么(以及为什么)时才应该这样做。 - mitchnull@SneakyThrows(InterruptedException.class)
lombok注释 :) - mitchnull传播InterruptException
恢复线程上的中断状态
或者:
根据您的情况以自定义方式处理中断是没有问题的。由于中断是终止请求而不是强制命令,因此完全可以完成其他工作以允许应用程序优雅地处理请求。例如,如果Thread正在睡眠、等待IO或硬件响应时收到Interrupt,则在终止线程之前优雅地关闭任何连接是完全有效的。
我强烈建议理解这个主题,但本文是信息的好来源:http://www.ibm.com/developerworks/java/library/j-jtp05236/