是的螺纹。中断()邪恶的?
-
19-09-2019 - |
题
队友提出以下要求:
"
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();
}
这对我们有两件事:
- 它避免吃掉中断的例外。 IDE自动外观处理程序始终为您提供类似的东西
ie.printStackTrace();
和一个jaunty“ todo:有用的东西需要去这里!”评论。 - 它可以恢复中断状态,而无需在此方法上强制检查例外。如果您要实现的方法签名没有
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()
国丢失。
问题不是说实现不是故障,而是您的线程被中断时处于未知状态,这可能导致不可预测的行为。