为什么吞咽InterruptedException确定Thread的子类?

时间:2009-05-20 02:04:38

标签: java multithreading exception-handling concurrency

在Brian Goetz的article on how to handle InterruptedException中,有一段突出:

  

当你知道线程即将退出时,吞下一个中断是可以接受的。只有当调用可中断方法的类是Thread的一部分而不是Runnable时,才会出现这种情况。

我不懂。是什么原因与Runnable可能由线程池处理,而线程是你自己开始的东西?

3 个答案:

答案 0 :(得分:4)

基本上。文章中表达的担忧是,如果你吞下中断异常,那么在堆栈中调用更高的代码将不会知道中断,可能导致不良行为。如果你启动线程,那么你就知道调用堆栈中没有任何东西可以关注被中断,这个线程不会继续存在于线程池中,所以只需让线程死掉。

我讨厌InterruptedException,我认为它给已检查的异常一个坏名称,本文不会改变这种观点。如果这个异常传递给调用堆栈非常重要,Runnable.run()应该在方法声明中声明它,这样你就可以简单地重新抛出它,或者它应该是一个未经检查的异常,出于同样的原因,SecurityException是未经检查的异常。

我最喜欢的设计是,如果你想知道它们被中断的话,方法会返回一个布尔值,但是这篇文章确实证明了那不一定是实用的。

答案 1 :(得分:3)

我认为延长Thread是不必要的,因此优先实施Runnable

但重要的是代码知道线程将要退出。如果您的代码是某些通用回调接口的一部分,那么您无法知道如何使用它。您可以传递给线程池(实际上,我们可能应该使用池而不是在代码中的不适当的位置构建Thread)。 OTOH,通常Runnable是一个匿名的内部类,因此,在源级别,是知道发生了什么的封闭方法的一部分。

因此,如果线程即将退出,则重置当前线程上的中断状态是没有意义的,因为没有什么可以中断。

在某些时候,你会想说它已经中断了。例如,即使在任务中断后,线程池也可以继续使用线程,尽管他们可能希望为试图接收任务的调用者保留InterruptException

库通常不能正确处理中断。 IMO,中断没有合理的上下文。没有它们,生活会变得更加简单,不幸的是,它们会让人感觉到它们。

答案 2 :(得分:2)

我同意其他人的看法,不同之处在于您是否控制该线程。如果您扩展了一个Thread,那么您可以控制该线程。另一方面,如果您的代码只是一个Runnable,它可能在您不拥有的借用线程(如线程池)上运行。通过吃掉异常而不是恢复中断状态,你就会剥夺代码更高的识别和处理中断的机会。

InterruptedException是一个经过检查的异常,我认为是一件好事。 InterruptedException是一种请求取消任务的方法。假设有人以Runnable的形式编写了一个任务,该任务涉及一个抛出InterruptedException的阻塞方法。如果它不是一个经过检查的例外,如果你不小心,你可能不会想到对InterruptedException采取行动(从而取消)并且你自己的清理

public class MyTask implements Runnable {
    public void run() {
        while (someCondition) {
            Object value = someBlockingQueue.take();
            // act on the value and loop back
        }
    }
}

由于InterruptedException是一个经过检查的异常,我的任务应如何响应中断(取消)是前端和中心。

public class MyTask implements Runnable {
    public void run() {
        while (someCondition) {
            try {
                Object value = someBlockingQueue.take();
                // act on the value and loop back
            } catch (InterruptedException e) {
                // I'm being cancelled; abort
                cleanUp();
                // restore the interrupt
                Thread.currentThread().interrupt();
                break;
            }
        }
    }
}