Java 为什么吞咽中断异常对于线程的子类是可以的?

Java 为什么吞咽中断异常对于线程的子类是可以的?,java,multithreading,exception-handling,concurrency,Java,Multithreading,Exception Handling,Concurrency,在布赖恩·戈茨(Brian Goetz)的著作中,有一段很突出: 接受中断的一次是当您知道线程即将退出时。只有当调用可中断方法的类是线程的一部分而不是可运行的时,才会出现这种情况 我不明白。原因是Runnable可能由线程池处理,而线程是您自己启动的吗 我认为扩展线程是不必要的,因此实现可运行是首选 但重要的是,代码知道线程将退出。如果您的代码是某些通用回调接口的一部分,那么您就不知道如何使用它。您可以被传递到线程池(实际上,我们可能应该使用池,而不是在代码中不适当的位置构建threads)。通

在布赖恩·戈茨(Brian Goetz)的著作中,有一段很突出:

接受中断的一次是当您知道线程即将退出时。只有当调用可中断方法的类是线程的一部分而不是可运行的时,才会出现这种情况


我不明白。原因是Runnable可能由线程池处理,而线程是您自己启动的吗

我认为扩展
线程
是不必要的,因此实现
可运行
是首选

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

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

在某个时刻,你会想说,它已经中断了足够的时间。例如,线程池即使在任务被中断后也可以继续使用线程,尽管它们可能希望保留
InterruptException
,以供尝试提取任务的调用方使用


库通常不能正确处理中断。在我看来,中断没有意义。没有它们,生活会简单得多,不幸的是,它们让人感觉到它们的存在。

基本上。文章中所表达的担忧是,如果您接受interupt异常,那么在堆栈中调用更高级别的代码将不知道该中断,这可能会导致不良行为。如果您启动线程,那么您知道调用堆栈中没有更高级别的线程关心被中断,这个线程将不会继续存在于线程池中,所以就让线程死吧

我讨厌InterruptedException,我认为它给选中的异常起了一个坏名字,本文并没有改变这种观点。如果此异常传递到调用堆栈非常重要,Runnable.run()应该在方法声明中声明它,以便您可以简单地重新调用它,或者它应该是未经检查的异常,原因与SecurityException是未经检查的异常相同


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

我同意其他人的观点,区别在于你是否控制该线程。如果你扩展了一个线程,你就可以控制这个线程。另一方面,如果您的代码只是一个可运行的代码,那么它可能会在您不拥有的借用线程(比如从线程池中)上运行。通过吃掉异常和不恢复中断状态,您剥夺了高级代码识别中断并对其采取行动的机会

我认为,InterruptedException作为一个已检查的异常是一件好事。InterruptedException是请求取消任务的一种方式。假设有人以Runnable的形式编写了一个任务,其中包含一个抛出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;
            }
        }
    }
}

实现Callable可能有助于返回布尔值。Callable还允许向上抛出异常。返回布尔值是个坏主意。如果不清除状态,则在典型的等待循环中丢失返回值并旋转。如果它没有清除状态,那么我们中断了线程。checked异常清楚地说明了这一点(也许,考虑到我看到的代码,不是所有人)。未经检查的异常可能会以合理的方式导致退出。@Yishai,我并不那么讨厌InterruptedException。从多线程的角度来看,从可中断的方法签名中知道这一点很好。@Tom Hawtin,考虑到本文的关注点,我同意将其设置为布尔值并不一定是个好主意。这对我来说绝对是有益的。也就是说,这里有很多折衷,实际经验表明,检查异常路径不起作用,基本上是因为重新刷新不是适当的响应-这是令人惊讶的,因此吞咽会导致错误处理。我认为最有可能的情况是,您希望执行清理()无论是否存在异常,它都应该存在于finally{}块中。