在Java中处理InterruptedException

问题

以下处理方式有什么区别InterruptedException?最好的方法是什么?

try{
 //...
} catch(InterruptedException e) { 
   Thread.currentThread().interrupt(); 
}

要么

try{
 //...
} catch(InterruptedException e) {
   throw new RuntimeException(e);
}

编辑:我也想知道这两个使用的场景。


#1 热门回答(281 赞)

你可能会问这个问题因为你调用了一个throwsInterruptedException的方法。

首先,你应该看到它是什么:throws InterruptedException:方法签名的一部分以及调用你正在调用的方法的可能结果。所以首先要接受这样一个事实,即aInterruptedException是方法调用的完全有效的结果。

现在,如果你正在调用的方法抛出此类异常,那么你应该做什么?你可以通过考虑以下问题找出答案:

你投入InterruptedException的方法是否有意义呢?换句话说,当你称之为方法时,这是一个明智的结果吗?

  • 如果是,则抛出InterruptedException应该是你的方法签名的一部分,并且你应该让异常传播(即根本不捕获它)。示例:你的方法等待来自网络的值以完成计算并返回结果。如果阻塞网络调用抛出InterruptedException,则你的方法无法以正常方式完成计算。你让InterruptedException传播。 int computeSum(服务器服务器)抛出InterruptedException {
        //传播下面抛出的任何InterruptedException
        int a = server.getValueA();
        int b = server.getValueB();
        返回b;
    }
  • 如果不是,那么你不应该使用抛出InterruptedException来声明你的方法,你应该(必须!)捕获异常。在这种情况下,现在要记住两件事很重要:有人打断了你的线程。有人可能急于取消操作,优雅地终止程序,或者其他什么。你应该对那个人保持礼貌并且不用再费力地从你的方法中回来。即使你的方法可以设法在InterruptedException的情况下产生合理的返回值,但线程已被中断的事实可能仍然很重要。特别是,调用方法的代码可能会对执行方法期间是否发生中断感兴趣。因此,你应该通过设置中断标志来记录中断发生的事实:Thread.currentThread()。interrupt()示例:用户要求打印两个值的总和。如果无法计算总和,则打印"无法计算总和"(并且比由于InterruptedException导致程序因堆栈跟踪而崩溃要好得多)。换句话说,使用抛出InterruptedException声明此方法没有意义。 void printSum(服务器服务器){
         尝试{
             int sum = computeSum(server);
             System.out.println("Sum:"sum);
         } catch(InterruptedException e){
             Thread.currentThread()中断(); //设置中断标志
             System.out.println("无法计算总和");
         }
    }

到目前为止,应该清楚的是,只做throw new RuntimeException(e)是一个坏主意。这对打电话者来说不太礼貌。你可以发明一个新的运行时异常,但根本原因(某人希望线程停止执行)可能会丢失。
其他示例:>实现Runnable:你可能已经发现,Runnable.run的签名不允许重新抛出InterruptedExceptions。好吧,你已注册实现Runnable,这意味着你已注册以处理可能的InterruptedExceptions。选择不同的界面,例如Callable,或者按照上面的第二种方法。

调用Thread.sleep:你正在尝试读取一个文件,规范说你应该尝试10次,间隔1秒。你调用Thread.sleep(1000)。所以,你需要处理InterruptedException。对于诸如tryToReadFile之类的方法,说"如果我被打断,我无法完成尝试读取文件的操作"是完全合理的。换句话说,抛出InterruptedExceptions的方法非常有意义。字符串tryToReadFile(File f)抛出InterruptedException {
    for(int i = 0; i <10; i){
        if(f.exists())
            return readFile(f);
        了Thread.sleep(1000);
    }
    return null;
}

此帖已被重写为文章here


#2 热门回答(71 赞)

碰巧我今天早上在Brian Goetz的Java Concurrency In Practice上班途中读到了这个。基本上他说你应该做两件事之一

  • 传播InterruptedException - 声明你的方法抛出已检查的InterruptedException,以便调用者必须处理它。
  • 恢复中断 - 有时你不能抛出InterruptedException。在这些情况下,你应该捕获InterruptedException并通过调用currentThread上的interrupt()方法来恢复中断状态,以便调用堆栈上方的代码可以看到发出了中断。

#3 热门回答(15 赞)

你想做什么?

当线程正在等待或休眠时,抛出InterruptedException,另一个线程使用classThread中的interrupt方法中断它。因此,如果你捕获此异常,则表示该线程已被中断。通常在调用Thread.currentThread().interrupt();时没有意义,除非你想从其他地方检查线程的"中断"状态。

关于你投掷aRuntimeException的其他选择,这似乎不是一件非常明智的事情(谁会抓住这个?它将如何处理?)但是如果没有其他信息就很难说清楚。