Thread.interrupt() 是邪恶的吗?

2022-09-01 06:30:53

一位队友提出了以下说法:

"Thread.interrupt()本质上是破碎的,应该(几乎)永远不要使用”。

我试图理解为什么会这样。

从不使用是已知的最佳做法吗?你能提供证据为什么它是坏的/有缺陷的,不应该用于编写健壮的多线程代码吗?Thread.interrupt()

注意 - 我对这个问题不感兴趣,如果它来自设计防腐剂的“漂亮”。我的问题是 - 它有缺陷吗?


答案 1

简短版本:

从不使用 Thread.interrupt() 是已知的最佳实践吗?

不。

你能提供证据证明为什么它被破坏/buggie,不应该用于编写健壮的多线程代码吗?

事实恰恰相反:这对于多线程代码至关重要。

有关示例,请参见 Java 并发实践中的清单 7.7。

加长版:

在这里,我们在一个特定的地方使用此方法: 处理 。这可能看起来有点奇怪,但这是它在代码中的样子:InterruptedExceptions

try {
    // Some code that might throw an InterruptedException.  
    // Using sleep as an example
    Thread.sleep(10000);
} catch (InterruptedException ie) {
    System.err.println("Interrupted in our long run.  Stopping.");
    Thread.currentThread().interrupt();
}

这为我们做了两件事:

  1. 它避免了中断异常。IDE 自动异常处理程序始终为您提供类似内容的内容,以及一个简短的“TODO:需要在此处访问有用的东西!”注释。ie.printStackTrace();
  2. 它恢复中断状态,而不会强制此方法上出现已检查的异常。如果要实现的方法签名没有子句,则这是传播中断状态的另一个选项。throws InterruptedException

一位评论者建议我应该使用一个未经检查的异常“来强制线程死亡”。这是假设我有先验的知识 突然杀死线程是正确的做法。我没有。

引用JCIP的Brian Goetz在上面引用的列表之前的页面上的话:

任务不应假定有关其执行线程的中断策略的任何信息,除非它被显式设计为在具有特定中断策略的服务中运行。

例如,假设我这样做了:

} catch (InterruptedException ie) {
    System.err.println("Interrupted in our long run.  Stopping.");
    // The following is very rude.
    throw new RuntimeException("I think the thread should die immediately", ie);
}

我会声明,无论调用堆栈的其余部分和关联状态的其他义务如何,此线程现在都需要死。我会尝试偷偷溜过所有其他捕获块和状态清理代码,以直接进入线程死亡。更糟糕的是,我会消耗线程的中断状态。上游逻辑现在必须解构我的异常,以尝试弄清楚是否存在程序逻辑错误,或者我是否试图在模糊包装器中隐藏已检查的异常。

例如,以下是团队中其他人必须立即执行的操作:

try {
    callBobsCode();
} catch (RuntimeException e) { // Because Bob is a jerk
    if (e.getCause() instanceOf InterruptedException) {
        // Man, what is that guy's problem?
        interruptCleanlyAndPreserveState();
        // Restoring the interrupt status
        Thread.currentThread().interrupt();
    }
}

中断状态比任何特定的 .有关具体原因的示例,请参阅 Thread.interrupt() 的 javadoc:InterruptException

如果在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者调用该类的 join()、join(long)、join(long、int)、sleep(long)或 sleep(long, int) 方法时阻塞此线程,则其中断状态将被清除,并且它将收到一个 InterruptedException。

如您所见,在处理中断请求时,可以创建和处理多个 InterruptedException,但前提是保留该中断状态。


答案 2

我所知道的唯一被破坏的方式是它实际上并没有做它看起来可能做的事情 - 它实际上只能中断侦听它的代码。Thread.interrupt()

但是,如果使用得当,在我看来,它是任务管理和取消的良好内置机制。

我推荐Java并发实践,以获取有关正确和安全使用它的更多信息。