在 Java 中处理 InterruptedException
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3976344/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Handling InterruptedException in Java
提问by devnull
What is the difference between the following ways of handling InterruptedException
? What is the best way to do it?
以下处理方式有什么区别InterruptedException
?最好的方法是什么?
try{
//...
} catch(InterruptedException e) {
Thread.currentThread().interrupt();
}
OR
或者
try{
//...
} catch(InterruptedException e) {
throw new RuntimeException(e);
}
EDIT: I'd like to also know in which scenarios are these two used.
编辑:我还想知道这两个在哪些场景中使用。
采纳答案by aioobe
What is the difference between the following ways of handling InterruptedException? What is the best way to do it?
以下处理 InterruptedException 的方式有什么区别?最好的方法是什么?
You've probably come to ask this question because you've called a method that throws InterruptedException
.
您可能会问这个问题,因为您调用了一个 throws 的方法InterruptedException
。
First of all, you should see throws InterruptedException
for what it is: A part of the method signature and a possible outcome of calling the method you're calling. So start by embracing the fact that an InterruptedException
is a perfectly valid result of the method call.
首先,您应该throws InterruptedException
了解它是什么:方法签名的一部分以及调用您正在调用的方法的可能结果。因此,首先要接受 anInterruptedException
是方法调用的完全有效结果这一事实。
Now, if the method you're calling throws such exception, what should yourmethod do? You can figure out the answer by thinking about the following:
现在,如果你调用的方法抛出了这样的异常,你的方法应该怎么做?你可以通过思考以下问题来找出答案:
Does it make sense for the method youare implementing to throw an InterruptedException
?Put differently, is an InterruptedException
a sensible outcome when calling yourmethod?
您正在实施的方法抛出一个有意义InterruptedException
吗?换句话说,InterruptedException
在调用您的方法时是一个明智的结果吗?
If yes, then
throws InterruptedException
should be part of yourmethod 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 yourmethod 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 notmake 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"); } }
如果是,那么
throws InterruptedException
应该是您的方法签名的一部分,并且您应该让异常传播(即根本不捕获它)。示例:您的方法等待来自网络的值以完成计算并返回结果。如果阻塞网络调用抛出一个
InterruptedException
你的方法不能以正常方式完成计算。你让InterruptedException
传播。int computeSum(Server server) throws InterruptedException { // Any InterruptedException thrown below is propagated int a = server.getValueA(); int b = server.getValueB(); return a + b; }
如果没有,那么你不应该用 with 声明你的方法,
throws InterruptedException
你应该(必须!)捕获异常。现在,在这种情况下要记住两件重要的事情:有人打断了你的话题。有人可能急于取消操作,优雅地终止程序,或者其他什么。你应该对那个人有礼貌,然后毫不费力地从你的方法中返回。
即使您的方法可以设法
InterruptedException
在线程被中断的情况下产生合理的返回值可能仍然很重要。特别是,调用您的方法的代码可能对您的方法执行期间是否发生中断感兴趣。因此,您应该通过设置中断标志来记录发生中断的事实:Thread.currentThread().interrupt()
示例:用户要求打印两个值的总和。
Failed to compute sum
如果无法计算总和,则打印 " " 是可以接受的(这比让程序因 堆栈跟踪而崩溃要好得多InterruptedException
)。换句话说,用 声明这个方法是没有意义的throws 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"); } }
By now it should be clear that just doing throw new RuntimeException(e)
is a bad idea. It isn't very polite to the caller. You could invent a new runtime exception but the root cause (someone wants the thread to stop execution) might get lost.
现在应该很清楚,只是做throw new RuntimeException(e)
是一个坏主意。这对来电者不是很礼貌。您可以发明一个新的运行时异常,但根本原因(有人希望线程停止执行)可能会丢失。
Other examples:
其他例子:
Implementing
Runnable
: As you may have discovered, the signature ofRunnable.run
does not allow for rethrowingInterruptedExceptions
. Well, yousigned up on implementingRunnable
, which means that yousigned up to deal with possibleInterruptedExceptions
. Either choose a different interface, such asCallable
, or follow the second approach above.
实施
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; }
调用
Thread.sleep
:您正在尝试读取文件,并且规范说您应该尝试 10 次,中间间隔 1 秒。你打电话Thread.sleep(1000)
。因此,您需要处理InterruptedException
. 对于诸如这样的方法tryToReadFile
来说,“如果我被打断了,我将无法完成尝试读取文件的操作”是完全合理的。换句话说,方法 throw 是完全合理的InterruptedExceptions
。String tryToReadFile(File f) throws InterruptedException { for (int i = 0; i < 10; i++) { if (f.exists()) return readFile(f); Thread.sleep(1000); } return null; }
This post has been rewritten as an article here.
这篇文章在这里被改写为一篇文章。
回答by Grodriguez
What are you trying to do?
你想做什么?
The InterruptedException
is thrown when a thread is waiting or sleeping and another thread interrupts it using the interrupt
method in class Thread
. So if you catch this exception, it means that the thread has been interrupted. Usually there is no point in calling Thread.currentThread().interrupt();
again, unless you want to check the "interrupted" status of the thread from somewhere else.
在InterruptedException
抛出时,一个线程正在等待或睡眠,并使用另一个线程中断它interrupt
在类方法Thread
。所以如果你捕捉到这个异常,就说明线程已经被中断了。通常没有必要Thread.currentThread().interrupt();
再次调用,除非您想从其他地方检查线程的“中断”状态。
Regarding your other option of throwing a RuntimeException
, it does not seem a very wise thing to do (who will catch this? how will it be handled?) but it is difficult to tell more without additional information.
关于你抛出 a 的其他选择RuntimeException
,这似乎不是一件非常明智的事情(谁会抓住这个?如何处理?)但如果没有额外的信息,很难说更多。
回答by mR_fr0g
As it happens I was just reading about this this morning on my way to work in Java Concurrency In Practiceby Brian Goetz. Basically he says you should do one of three things
碰巧的是,我今天早上刚在去工作的路上读到了 Brian Goetz 撰写的Java Concurrency In Practice。基本上他说你应该做三件事之一
Propagate the
InterruptedException
- Declare your method to throw the checkedInterruptedException
so that your caller has to deal with it.Restore the Interrupt- Sometimes you cannot throw
InterruptedException
. In these cases you should catch theInterruptedException
and restore the interrupt status by calling theinterrupt()
method on thecurrentThread
so the code higher up the call stack can see that an interrupt was issued, and quickly return from the method. Note: this is only applicable when your method has "try" or "best effort" semantics, i. e. nothing critical would happen if the method doesn't accomplish its goal. For example,log()
orsendMetric()
may be such method, orboolean tryTransferMoney()
, but notvoid transferMoney()
. See herefor more details.- Ignore the interruption within method, but restore the status upon exit- e. g. via Guava's
Uninterruptibles
.Uninterruptibles
take over the boilerplate code like in the Noncancelable Task example in JCIP § 7.1.3.
传播
InterruptedException
- 声明您的方法以抛出已检查的内容,InterruptedException
以便您的调用者必须处理它。恢复中断- 有时您不能抛出
InterruptedException
. 在这些情况下,您应该InterruptedException
通过调用interrupt()
方法捕获并恢复中断状态,currentThread
以便调用堆栈上层的代码可以看到发出了中断,并快速从方法返回。注意:这仅适用于您的方法具有“尝试”或“尽力而为”语义时,即如果该方法没有实现其目标,则不会发生任何重要的事情。例如,log()
或者sendMetric()
可能是这样的方法,或者boolean tryTransferMoney()
,但不是void transferMoney()
。请参阅此处了解更多详情。- 忽略方法中的中断,但在退出时恢复状态- 例如通过 Guava 的
Uninterruptibles
.Uninterruptibles
像 JCIP § 7.1.3 中的不可取消任务示例一样接管样板代码。
回答by Nathan Hughes
To me the key thing about this is: an InterruptedException is not anything going wrong, it is the thread doing what you told it to do. Therefore rethrowing it wrapped in a RuntimeException makes zero sense.
对我来说,关键是:InterruptedException 没有任何问题,它是线程按照您的指示执行操作。因此,重新抛出它包装在 RuntimeException 中是零意义的。
In many cases it makes sense to rethrow an exception wrapped in a RuntimeException when you say, I don't know what went wrong here and I can't do anything to fix it, I just want it to get out of the current processing flow and hit whatever application-wide exception handler I have so it can log it. That's not the case with an InterruptedException, it's just the thread responding to having interrupt() called on it, it's throwing the InterruptedException in order to help cancel the thread's processing in a timely way.
在许多情况下,当您说我不知道这里出了什么问题并且我无法做任何事情来修复它时,重新抛出一个包含在 RuntimeException 中的异常是有意义的,我只是想让它脱离当前的处理流程并点击我拥有的任何应用程序范围的异常处理程序,以便它可以记录它。InterruptedException 不是这种情况,它只是响应调用了 interrupt() 的线程,它抛出 InterruptedException 以帮助及时取消线程的处理。
So propagate the InterruptedException, or eat it intelligently (meaning at a place where it will have accomplished what it was meant to do) and reset the interrupt flag. Note that the interrupt flag gets cleared when the InterruptedException gets thrown; the assumption the Jdk library developers make is that catching the exception amounts to handling it, so by default the flag is cleared.
所以传播 InterruptedException,或者聪明地吃掉它(意思是在它完成它应该做的事情的地方)并重置中断标志。请注意,当抛出 InterruptedException 时,中断标志会被清除;Jdk 库开发人员所做的假设是捕获异常相当于处理它,因此默认情况下清除该标志。
So definitely the first way is better, the second posted example in the question is not useful unless you don't expect the thread to actually get interrupted, and interrupting it amounts to an error.
所以肯定第一种方法更好,问题中的第二个发布示例没有用,除非您不希望线程实际上被中断,并且中断它相当于一个错误。
Here's an answer I wrote describing how interrupts work, with an example. You can see in the example code where it is using the InterruptedException to bail out of a while loop in the Runnable's run method.
这是我写的一个答案,描述了中断的工作方式,并举了一个例子。您可以在示例代码中看到它使用 InterruptedException 来退出 Runnable 的 run 方法中的 while 循环。
回答by nedruod
The correct default choice is add InterruptedException to your throws list. An Interrupt indicates that another thread wishes your thread to end. The reason for this request is not made evident and is entirely contextual, so if you don't have any additional knowledge you should assume it's just a friendly shutdown, and anything that avoids that shutdown is a non-friendly response.
正确的默认选择是将 InterruptedException 添加到您的抛出列表中。中断表示另一个线程希望您的线程结束。这个请求的原因并不明显,完全是上下文,所以如果你没有任何额外的知识,你应该假设它只是一个友好的关闭,避免关闭的任何事情都是非友好的响应。
Java will not randomly throw InterruptedException's, all advice will not affect your application but I have run into a case where developer's following the "swallow" strategy became very inconvenient. A team had developed a large set of tests and used Thread.Sleep a lot. Now we started to run the tests in our CI server, and sometimes due to defects in the code would get stuck into permanent waits. To make the situation worse, when attempting to cancel the CI job it never closed because the Thread.Interrupt that was intended to abort the test did not abort the job. We had to login to the box and manually kill the processes.
Java 不会随机抛出 InterruptedException 的,所有建议都不会影响您的应用程序,但我遇到过这样一种情况,即开发人员遵循“吞咽”策略变得非常不方便。一个团队开发了大量测试并大量使用 Thread.Sleep。现在我们开始在我们的 CI 服务器中运行测试,有时由于代码中的缺陷会陷入永久等待。更糟糕的是,当尝试取消 CI 作业时,它从未关闭,因为旨在中止测试的 Thread.Interrupt 没有中止作业。我们必须登录到该框并手动终止进程。
So long story short, if you simply throw the InterruptedException you are matching the default intent that your thread should end. If you can't add InterruptedException to your throw list, I'd wrap it in a RuntimeException.
长话短说,如果您只是抛出 InterruptedException,您就匹配了您的线程应该结束的默认意图。如果您不能将 InterruptedException 添加到您的抛出列表中,我会将其包装在 RuntimeException 中。
There is a very rational argument to be made that InterruptedException should be a RuntimeException itself, since that would encourage a better "default" handling. It's not a RuntimeException only because the designers stuck to a categorical rule that a RuntimeException should represent an error in your code. Since an InterruptedException does not arise directly from an error in your code, it's not. But the reality is that often an InterruptedException arises because there is an error in your code, (i.e. endless loop, dead-lock), and the Interrupt is some other thread's method for dealing with that error.
有一个非常合理的论点认为 InterruptedException 应该是 RuntimeException 本身,因为这会鼓励更好的“默认”处理。它不是 RuntimeException 仅仅因为设计者坚持一个分类规则,即 RuntimeException 应该代表您的代码中的错误。由于 InterruptedException 不是直接由代码中的错误引起的,因此不是。但实际情况是,由于代码中存在错误(即无限循环、死锁),通常会出现 InterruptedException,而 Interrupt 是其他线程处理该错误的方法。
If you know there is rational cleanup to be done, then do it. If you know a deeper cause for the Interrupt, you can take on more comprehensive handling.
如果您知道需要进行合理的清理,那就去做吧。如果您知道中断的更深层次原因,则可以进行更全面的处理。
So in summary your choices for handling should follow this list:
因此,总而言之,您的处理选择应遵循以下列表:
- By default, add to throws.
- If not allowed to add to throws, throw RuntimeException(e). (Best choice of multiple bad options)
- Only when you know an explicit cause of the Interrupt, handle as desired. If your handling is local to your method, then reset interrupted by a call to Thread.currentThread().interrupt().
- 默认情况下,添加到 throws。
- 如果不允许添加到 throws,则抛出 RuntimeException(e)。(多个坏选项的最佳选择)
- 只有当您知道中断的明确原因时,才按需要进行处理。如果您的处理是您的方法的本地处理,则重置被调用 Thread.currentThread().interrupt() 中断。
回答by TheIT
I just wanted to add one last option to what most people and articles mention. As mR_fr0g has stated, it's important to handle the interrupt correctly either by:
我只是想在大多数人和文章提到的内容中添加最后一个选项。正如 mR_fr0g 所说,通过以下方式正确处理中断很重要:
Propagating the InterruptException
Restore Interrupt state on Thread
传播中断异常
在线程上恢复中断状态
Or additionally:
或者另外:
- Custom handling of Interrupt
- 中断的自定义处理
There is nothing wrong with handling the interrupt in a custom way depending on your circumstances. As an interrupt is a request for termination, as opposed to a forceful command, it is perfectly valid to complete additional work to allow the application to handle the request gracefully. For example, if a Thread is Sleeping, waiting on IO or a hardware response, when it receives the Interrupt, then it is perfectly valid to gracefully close any connections before terminating the thread.
根据您的情况以自定义方式处理中断并没有错。由于中断是终止请求,而不是强制命令,因此完成额外工作以允许应用程序优雅地处理请求是完全有效的。例如,如果一个线程正在休眠,等待 IO 或硬件响应,当它收到中断时,那么在终止线程之前优雅地关闭任何连接是完全有效的。
I highly recommend understanding the topic, but this article is a good source of information: http://www.ibm.com/developerworks/java/library/j-jtp05236/
我强烈建议您理解该主题,但这篇文章是一个很好的信息来源:http: //www.ibm.com/developerworks/java/library/j-jtp05236/
回答by Bjarne Bostr?m
I would say in some cases it's ok to do nothing. Probably not something you should be doing by default, but in case there should be no way for the interrupt to happen, I'm not sure what else to do (probably logging error, but that does not affect program flow).
我会说在某些情况下什么都不做也可以。可能不是默认情况下您应该做的事情,但是如果没有办法让中断发生,我不确定还能做什么(可能记录错误,但这不会影响程序流程)。
One case would be in case you have a task (blocking) queue. In case you have a daemon Thread handling these tasks and you do not interrupt the Thread by yourself (to my knowledge the jvm does not interrupt daemon threads on jvm shutdown), I see no way for the interrupt to happen, and therefore it could be just ignored. (I do know that a daemon thread may be killed by the jvm at any time and therefore are unsuitable in some cases).
一种情况是,如果您有一个任务(阻塞)队列。如果您有一个守护线程处理这些任务并且您没有自己中断线程(据我所知,jvm 不会在 jvm 关闭时中断守护线程),我认为中断不可能发生,因此它可能是只是忽略。(我知道守护线程可能随时被 jvm 杀死,因此在某些情况下不合适)。
EDIT: Another case might be guarded blocks, at least based on Oracle's tutorial at: http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
编辑:另一种情况可能是受保护的块,至少基于 Oracle 的教程:http: //docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html