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

时间:2021-10-18 07:08:46

In Brian Goetz's article on how to handle InterruptedException, one paragraph stands out:

在Brian Goetz关于如何处理InterruptedException的文章中,有一段突出:

The one time it's acceptable to swallow an interrupt is when you know the thread is about to exit. This scenario only occurs when the class calling the interruptible method is part of a Thread, not a Runnable.

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

I don't get this. Is the reason something to do with the Runnable possibly being handled by a threadpool whereas the Thread is something you start on your own ?

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

3 个解决方案

#1


Basically. The concern expressed in the article is that if you swallow the interupt exception then calling code higher in the stack won't know about the interuption, possibly causing undesirable behavior. If you start the thread, then you know there is nothing higher in the call stack that cares about being interupted, this thread will not continue to live in a thread pool, so just let the thread die.

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

I hate InterruptedException, I think it gives checked exceptions a bad name, and this article doesn't change that perspective. If it was so important that this exception pass up the call stack, Runnable.run() should have it declared in the method declaration so you can simply rethrow it, or it should have been an unchecked exception for the same reason SecurityException is an unchecked exception.

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

My prefered design would be that the methods return a boolean if they were interrupted if you care to know, but this article does make the case that that wouldn't necessarily be practical.

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

#2


I would argue that extending Thread there was unnecessary, and therefore implementing Runnable is preferred.

我认为扩展Thread是不必要的,因此实现Runnable是首选。

But the important thing is that the code knows the thread is going to exit. If your code is part of some generic callback interface then you can't know how you are being used. You could be passed to a thread pool (indeed, we probably should be using pools rather than constructing Threads at inappropriate points in the code). OTOH, usually the Runnable is an anonymous inner class and therefore, at a source level, part of the enclosing method that does know what is going on.

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

So, if the thread is about to exit, resetting the interrupt state on the current thread is pointless because there is nothing to interrupt.

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

At some point you are going to want to say that it has interrupted enough. Thread pools for instance can continue to use a thread even after a task has been interrupted, although they might want to keep the InterruptException around for the callers that attempt to pick up the task.

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

Libraries generally do not handle interrupts correctly. IMO, interrupts don't have the context to make sense. Life would be a lot simpler without them, unfortunately they make their presence felt.

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

#3


I agree with the others that the difference is whether you control that thread or not. If you extended a Thread, it's pretty much a given that you have control over that thread. On the other hand, if your code is simply a Runnable, it might be run on a borrowed thread (like from a thread pool) you do not own. By eating up the exception and not restoring the interrupt status, you deprive the code higher-up of the chance to recognize and act on the interruption.

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

InterruptedException being a checked exception is, I think, a good thing. An InterruptedException is a way to request a cancellation of tasks. Suppose one wrote a task in the form of a Runnable that involves a blocking method that throws an InterruptedException. If it were not a checked exception, if you're not being careful you may not think to act on the InterruptedException (thus cancellation) and do your own clean-up.

我认为,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
        }
    }
}

Since InterruptedException is a checked exception, how my task should respond to interruption (cancellation) is front and center.

由于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;
            }
        }
    }
}

#1


Basically. The concern expressed in the article is that if you swallow the interupt exception then calling code higher in the stack won't know about the interuption, possibly causing undesirable behavior. If you start the thread, then you know there is nothing higher in the call stack that cares about being interupted, this thread will not continue to live in a thread pool, so just let the thread die.

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

I hate InterruptedException, I think it gives checked exceptions a bad name, and this article doesn't change that perspective. If it was so important that this exception pass up the call stack, Runnable.run() should have it declared in the method declaration so you can simply rethrow it, or it should have been an unchecked exception for the same reason SecurityException is an unchecked exception.

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

My prefered design would be that the methods return a boolean if they were interrupted if you care to know, but this article does make the case that that wouldn't necessarily be practical.

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

#2


I would argue that extending Thread there was unnecessary, and therefore implementing Runnable is preferred.

我认为扩展Thread是不必要的,因此实现Runnable是首选。

But the important thing is that the code knows the thread is going to exit. If your code is part of some generic callback interface then you can't know how you are being used. You could be passed to a thread pool (indeed, we probably should be using pools rather than constructing Threads at inappropriate points in the code). OTOH, usually the Runnable is an anonymous inner class and therefore, at a source level, part of the enclosing method that does know what is going on.

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

So, if the thread is about to exit, resetting the interrupt state on the current thread is pointless because there is nothing to interrupt.

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

At some point you are going to want to say that it has interrupted enough. Thread pools for instance can continue to use a thread even after a task has been interrupted, although they might want to keep the InterruptException around for the callers that attempt to pick up the task.

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

Libraries generally do not handle interrupts correctly. IMO, interrupts don't have the context to make sense. Life would be a lot simpler without them, unfortunately they make their presence felt.

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

#3


I agree with the others that the difference is whether you control that thread or not. If you extended a Thread, it's pretty much a given that you have control over that thread. On the other hand, if your code is simply a Runnable, it might be run on a borrowed thread (like from a thread pool) you do not own. By eating up the exception and not restoring the interrupt status, you deprive the code higher-up of the chance to recognize and act on the interruption.

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

InterruptedException being a checked exception is, I think, a good thing. An InterruptedException is a way to request a cancellation of tasks. Suppose one wrote a task in the form of a Runnable that involves a blocking method that throws an InterruptedException. If it were not a checked exception, if you're not being careful you may not think to act on the InterruptedException (thus cancellation) and do your own clean-up.

我认为,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
        }
    }
}

Since InterruptedException is a checked exception, how my task should respond to interruption (cancellation) is front and center.

由于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;
            }
        }
    }
}