队友提出以下要求:

"Thread.interrupt() 是的固有破坏,并应(几乎)永远不会使用"。

我试着去了解为什么是这种情况。

它是一个已知的最佳实践中从来没有使用 Thread.interrupt()?你能提供证据证明它为什么被破坏/越野车,而不应被用于编写强大的多线程的代码?

注意到 -我不感兴趣在这个问题如果这是"漂亮的"从设计的防腐剂。我的问题-这是越野车?

有帮助吗?

解决方案

精简版:

它是已知的最佳实践,永远不要使用thread.intrupr()?

不。

您能否提供证据,为什么它被打破 / buggie,不应用于编写强大的多线程代码?

相反的是:这对于多线程代码至关重要。

请参阅列表7.7 in 实践中的Java并发 例如。

更长的版本:

在这里,我们在一个特定的地方使用此方法:处理 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自动外观处理程序始终为您提供类似的东西 ie.printStackTrace(); 和一个jaunty“ todo:有用的东西需要去这里!”评论。
  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();
    }
}

中断状态比任何特定的 InterruptException. 。有关特定示例的原因,请参见Javadoc thread.interrupt():

如果此线程在wait()的调用中被阻止,请wait(long)或wate(long,int)对象类或join()的方法(),join(long),join(long,int) ,睡眠(长)或睡眠(长,int),该类别的方法,然后将清除其中断状态,并将收到中断的exception。

如您所见,随着中断请求的处理,可以创建和处理多个中断的exception,但只有保留了中断状态。

其他提示

我知道哪个 Thread.interrupt() 被打破了,它实际上并没有做似乎可能的事情 - 它实际上只能 打断 倾听它的代码。

但是,正确使用的是,在我看来,它就像是一个好的内置机制,用于任务管理和取消。

我建议 实践中的Java并发 有关适当和安全的使用情况的更多阅读。

主要问题 Thread.interrupt() 是大多数程序员不知道隐藏的陷阱,而是以错误的方式使用它。例如,当您处理中断时,有一些方法 清除 国旗(因此状态丢失)。

另外,呼叫并不总是会立即中断线程。例如,当它悬挂在某些系统例程中时,什么都不会发生。实际上,如果线程未检查标志,并且永远不会调用抛出的Java方法 InterruptException, ,然后中断它不会产生任何效果。

不,这不是越野车。实际上,这是您如何停止Java中线程的基础。它在java.util.concurrent的执行程序框架中使用 - 请参阅实现 java.util.concurrent.FutureTask.Sync.innerCancel.

至于失败,我从未见过失败,而且我已经广泛使用了它。

未提及的一个原因是,中断信号可能会丢失,从而使thread.intrupp()方法无意义。因此,除非您在thread.run()方法中的代码在一段时间内旋转,否则调用thread.inter.inter.inter.intrupl()的结果尚不确定。

我注意到,当在线程 ONE 我的执行 DriverManager.getConnection() 当没有数据库连接设备(服务器说是下来,从而最后这条线引发 SQLException)和从螺纹 TWO 我明确地呼叫 ONE.interrupt(), 然后两个 ONE.interrupted()ONE.isInterrupted() 返回 false 甚至如果放在作为第一线的 catch{} 块在哪里 SQLException 处理。

当然,我workarounded这一问题实施的额外信号,但这是相当麻烦,因为它是第一个这样的问题在我15年Java发展。

我想这是因为在错误 com.microsoft.sqlserver.jdbc.SQLServerDriver.和我调查更多的确认,呼叫的 native 功能所消耗的这一例外在所有情况下,它trhows自己,但保留它当成功。

托梅克

P.S.我发现的 类似的问题.

P.P.S 我将非常简短的例子是什么我的留言上。登记类可以发现在 sqljdbc42.jar.我发现了这个错误,在课程建立在2015-08-20然后我更新的最新版本(从2017-01-12)和错误仍然存在。

import java.sql.*;

public class TEST implements Runnable{
    static{
        try{
//register the proper driver
           Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
        }
        catch(ClassNotFoundException e){
            System.err.println("Cannot load JDBC driver (not found in CLASSPATH).");
        }
    }

    public void run() {
        Thread.currentThread().interrupt();
        System.out.println(Thread.currentThread().isInterrupted());
//prints true
        try{
            Connection conn = DriverManager.getConnection("jdbc:sqlserver://xxxx\\xxxx;databaseName=xxxx;integratedSecurity=true");
        }
        catch (SQLException e){
            System.out.println(e.getMessage());
        }
        System.out.println(Thread.currentThread().isInterrupted());
//prints false
        System.exit(0);
    }

    public static void main(String[] args){
        (new Thread(new TEST())).start();
    }
}

如果你通过一些完全不正确的,因为 "foo", , DriverManager.getConnection(), 你会得到消息"没有合适的司机找到foo",并将第二个打印输出将仍然是真实的,作为一个希望。但如果你通过正确的建串但是,说的,你的服务器或者你失去了你的网络连接(即通常可以occurr在生产环境中),将会看到的 java.net 插座超时错误的打印输出和螺纹的 interrupted() 国丢失。

问题不是说实现不是故障,而是您的线程被中断时处于未知状态,这可能导致不可预测的行为。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top