如果没有人调用interrupt(),可以忽略InterruptedException吗?

时间:2015-02-16 15:31:49

标签: java multithreading exception-handling thread-safety interrupted-exception

如果我创建自己的线程(即不是线程池)和某个地方我调用sleep或任何其他可中断的方法,如果我知道代码中没有其他人在做什么就可以忽略InterruptedException 线程上的中断

换句话说,如果线程应该和JVM一样长,这意味着线程不可中断,可以安全地假设InterruptedException将从不被调用,因此异常可以被吞下了?

8 个答案:

答案 0 :(得分:32)

忽略已检查的异常从不被视为安全。
你现在可能没问题,但是如果另一个程序员扩展你的代码,他会期望标准行为:线程对中断调用作出反应。
在这种情况下,一个空的catch块也很危险,因为JVM删除了中断的标志,它应该再次设置

Thread.currentThread().interrupt();

在catch块中。在我看来,这是InterruptedException的最小捕获实现。在循环中检查isInterrupted标志也不会造成太大影响。
与您未来的程序员自己一两天的麻烦搜索意外的线程行为相比,这是一个很小的开销,因为您的项目可能会有所增长。

如果您认为代码的可读性受到这些catch实现的影响,您可以实现自己的safeSleep实用程序方法,该方法负责Exception并正确设置标记。

另一方面,如果硬件发生故障,JVM本身不会抛出InterruptedException仅指示Exception 的用户。 因此,如果您没有传播Thread个引用,则不会有任何其他Thread能够在其上调用Thread.interrupt()这是它技术上但是你不应该低估人为因素和你的程序演变。
修改:正如 ruakh 所指出的,实际上有一种方法可以获得Thread的引用,从而安排Thread.interrupt()来电。这样,开发人员可能甚至不必查看实现不间断Thread的类。在我看来,这是另一个原因,即实施适当的异常处理 另一件事:如果你没有抛出Exception,那么在INFO之外的某个级别记录此类事件可能是一个不错的选择。

答案 1 :(得分:32)

如果你确定它永远不会发生,你可以崩溃而不是忽视它,而不是吞下它。例如,抛出Error(或RuntimeException):

try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    throw new Error(e);
}

来自the Javadocs for Error

  

错误是Throwable的子类,表示合理的应用程序不应该尝试捕获的严重问题。大多数此类错误都是异常情况。

如果您认为值得假设某些事情永远不会发生,那么如果确实发生了这种情况,那就是“异常情况”"那个,谁知道,可能只是一个严重的问题"。

另一种看待这种情况的方法是,如果将来有人 中断您的方法,他们是否有可能希望它继续运行,好像什么也没发生过?我猜不会。

答案 2 :(得分:16)

如果您认为永远不会发生异常,则不应该吞下异常。可以决定不添加处理从未发生的条件的代码,但不应该发生静默

你应该做的最低限度是:

catch(InterruptedException ex) {
  throw new AssertionError(ex);
}

这可以确保无论何时断言这种情况永远不会发生,您都会注意到。此模式也适用于其他意外例外,例如IOException当您知道目标OutputStreamByteArrayOutputStreamAppendable Formatter应该是StringBuilder时,等等< / p>


顺便说一下,Thread.sleep还有一个替代方案,根本不需要处理InterruptedException

LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(timeInMillis));

当线程被中断并且保持Thread的中断状态时,此方法将简单地返回,因此它为所做的其他人使用您的代码的情况提供了正确的处理使用中断(假设代码的调用者检查中断状态)。

答案 3 :(得分:9)

关于这些问题,我仍然认为圣经的书,Goetz等。 Java Concurrency in Practice 在第7章中提到了以下重要内容(Goetz的developerWorks article中有相同的材料,它具有免费的优势,但本书更多一点在某些方面明确。)

  

中断是一种合作机制。一个线程不能强制另一个   停止它正在做的事情并做其他事情;当线程A中断线程B时,A只是要求B在到达方便的停止点时停止它正在做的事情 - 如果感觉就好了。

     

[...]

     

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

所以,是的,你可以在你概述的情况下“吞下”InterruptedException

这本书中也很重要:

  

因为每个线程都有自己的中断策略,所以不应该中断   一个线程,除非你知道中断对该线程意味着什么。

因此,您可以选择自己的策略,例如使用RuntimeExceptionAssertionError“崩溃”,只需将其记录为警告,或者只要您为其他任何人记录此问题而完全忽略中断需要知道。什么是最好的取决于你的线程在做什么,你没有提供任何细节。例如,如果它在火箭上运行[比如说做态度控制],你不想让JVM /火箭崩溃只是因为一个同事程序员[甚至可能不和你在同一家公司工作,例如他写了一些你称之为的图书馆忘记了他的代码中的某个合同并将一个安全可忽略的例外转储给你:"The exception which occurred was not due to random failure but a design error."

答案 4 :(得分:7)

如果你的Projekt变得越来越复杂,那就越来越难以说绝对没有人会调用中断方法。如果有人在某一天调用此方法并且发生InterruptedException,那么如果您至少没有在某处记录它,那么调试它真的很难。

答案 5 :(得分:6)

不应该被忽视。它应该被抛回调用者,或者你应该重新设置线程的中断状态,该状态在抛出异常时被清除:

catch (InterruptedException e) { 
     // Restore the interrupted status
     Thread.currentThread().interrupt();
 }

除非你提示在catch之后退出线程。

Here是一篇关于处理InterruptedException的文章。

答案 6 :(得分:2)

  

如果线程应该与JVM一样长,这意味着线程不可中断,可以安全地假设InterruptedException从不抛出,因此异常可以被吞下了?

我理解你的痛苦,没有商业价值的样板试用块的激增会伤害代码。

如果您打算吞下异常的代码完全在您的控制之下,并且它只是客户端代码(它永远不会在您自己的上下文中重复使用),那么它是可以安全地吞下这个例外。请注意,那里有很多 if

如果你碰巧使用Java 8,你有另一个选项,描述为here:将你的代码包装在uncheckCall(() -> { ... })块中。这使代码块抛出InterruptedException而不声明它。正如链接答案中所解释的那样,应该非常谨慎地处理,但它有可能使您的代码非常干净。

答案 7 :(得分:1)

我认为,忽略InterruptedException是否安全,取决于你在该线程中做了什么。如果有任何情况,当您的线程发生意外中断时,系统或任何资源处于不需要的状态(脏,锁定,未释放,可能导致资源泄漏),那么您有责任处理InterruptedException并且不应忽略它。您是否希望自己的线程可以中断,这取决于您。

换句话说,中断机制主要用于实现取消策略和任务清理。你在任务中没有任何东西要清理,或者你没有任何特定的任务取消政策,忽略IntrruptedException可能听起来没有政治正确但是没问题。