如果我自己没有中断任何东西,我是否需要担心InterruptedException?

35

我在一个业余项目中使用java.util.concurrent.Semaphore。它被用于我正在编写的连接池类中。除了这个方法,我几乎可以毫不费力地使用它:

public void acquire(int permits) throws InterruptedException

这迫使我处理InterruptedException异常。现在,我不确定"中断"线程的含义,也从未在我的代码中显式实现过。这是否意味着我可以忽略该异常?我应该如何处理它?

5个回答

35

是的,你需要担心InterruptedException,就像你需要担心其他必须抛出或处理的已检查异常一样。

大多数情况下,InterruptedException表示停止请求,很可能是由于运行代码的线程被interrupted

在你等待获取连接的连接池的特定情况下,我会说这是一个取消问题,你需要中止获取、清理和恢复中断标志(见下文)。


作为一个例子,如果你正在使用某种在Executor内运行的Runnable/Callable,那么你需要正确处理InterruptedException:
executor.execute(new Runnable() {

    public void run() {
         while (true) {
              try {
                 Thread.sleep(1000);
              } catch ( InterruptedException e) {
                  continue; //blah
              }
              pingRemoteServer();
         }
    }
});

这意味着你的任务不遵循执行器使用的中断机制,也不能正确地取消/关闭。
相反,正确的惯用法是恢复被中断的状态,然后停止执行:
executor.execute(new Runnable() {

    public void run() {
         while (true) {
              try {
                 Thread.sleep(1000);
              } catch ( InterruptedException e) {
                  Thread.currentThread().interrupt(); // restore interrupted status
                  break;
              }
              pingRemoteServer();
         }
    }
});

有用的资源:


3
当然。了解更多信息,请参阅Java专家通讯(http://www.javaspecialists.co.za/archive/Issue056.html)。 - Brian Agnew
1
应该使用Thread.currentThread().interrupt()而不是Thread.interrupted()吧?根据javadoc,Thread.interrupted()会清除中断标志,而不是设置它。 - Joe Daley

7
不是的。只有在您自己中断线程时才会生成 InterruptedException。如果您没有使用 Thread.interrupt(),那么我会将其重新抛出为某种“意外异常”,或将其记录为错误并继续执行。例如,在我的代码中,当我被迫捕获 InterruptedException 但我从未调用过 interrupt() 时,我会执行相当于:
catch (InterruptedException exception) {
    throw new RuntimeException("Unexpected interrupt", exception);
}

如果中断是意外发生的,那么就需要进行处理。但在许多情况下,我会有意中断我的线程,在这种情况下,我会以明确定义的方式处理InterruptedException异常。通常,我会退出当前循环、清理资源,然后停止线程。


2

通过调用Thread.interrupt()可以中断线程。这通常用于优雅地向线程发送信号,让其执行其他任务。通常会导致阻塞操作(例如Thread.sleep())提前返回并抛出InterruptedException异常。如果线程被中断,它会设置一个标志。可以通过Thread.isInterrupted()调用查询此标志。

如果您不使用线程中断而仍然收到此异常,可以直接退出线程(最好记录异常)。

总的来说,这取决于您多线程应用程序的实际情况。


1

如果你不知道如何在方法中处理它,我建议你在方法中声明 throws InterruptedException(以及调用者等)

如果这是你从未预料到的情况,我会捕获它并将其包装在 AssertionError 中。


0

在执行任何线程所需的清理工作后,应该退出run()方法。
希望对你有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接