Thread.stop和朋友在Java中是否安全?

Ste*_*n C 43 java multithreading

stop(),suspend()以及resume()java.lang.Thread已被弃用,因为它们是不安全的.Sun推荐的解决方法是使用Thread.interrupt(),但这种方法并不适用于所有情况.例如,如果您调用未明确或隐式检查interrupted标志的库方法,则您别无选择,只能等待调用完成.

所以,我想知道是否有可能描述调用stop()线程(可证明)安全的情况.例如,这将是安全的,stop()一个线程,什么也没做,但通话find(...)还是match(...)一个java.util.regex.Matcher

(如果有任何Sun工程师正在阅读这篇文章......我将非常感谢您的确切答案.)

编辑:简单地重述您不应该调用的口头禅的答案,stop()因为它已被弃用,不安全,无论什么都缺少这个问题的要点.我知道在大多数情况下它确实是不安全的,并且如果有可行的替代方案,你应该总是使用它.

这个问题是关于安全的子集案例.具体来说,什么是子集?

Ste*_*n C 19

这是我尝试回答我自己的问题.

我认为以下条件应足以使用Thread.stop()以下方法安全地停止单个线程:

  1. 线程执行不得创建或改变在线程停止时其他线程可能看到的任何状态(即Java对象,类变量,外部资源).
  2. notify在正常执行期间,线程执行不得用于任何其他线程.
  3. 线程必须没有startjoin其他线程,或与之交互使用stop,suspendresume.

(上面的线程执行一词涵盖了所有应用程序级代码和线程执行的所有库代码.)

第一个条件意味着停止的线程不会使任何外部数据结构或资源处于不一致状态.这包括它可能在互斥锁中访问(读取)的数据结构.第二个条件意味着可停止的线程不能让其他线程等待.但它也禁止使用任何其他简单对象互斥体的同步机制.

可停止的线程必须有一种方法将每个计算的结果传递给控制线程.这些结果由可停止的线程创建/变异,因此我们只需要确保它们在线程停止后不可见.例如,结果可以分配给Thread对象的私有成员,并用一个标志"保护",该标志由线程原子地说它是"完成".

编辑:这些条件相当严格.例如,对于要安全停止的"正则表达式求值程序"线程,如果我们必须保证正则表达式引擎不会改变任何外部可见状态.问题是它可能会这样做,具体取决于你如何实现线程!

  1. 这些Pattern.compile(...)方法可能会更新已编译模式的静态缓存,如果有,他们会(应该)使用互斥来执行此操作.(实际上,OpenJDK 6.0版本不会缓存模式,但Sun可能会改变这种情况.)
  2. 如果你试图通过在控制线程中编译正则表达式并提供预先实例化来避免1)Matcher,那么正则表达式线程确实会改变外部可见状态.

在第一种情况下,我们可能会遇到麻烦.例如,假设使用HashMap实现缓存,并且在重组HashMap时线程被中断.

在第二种情况下,我们将确定提供的是Matcher尚未传递到其他线程,并提供了该控制器的线程没有尝试使用Matcher停药正则表达式匹配跟帖.

那么这又给我们留下了什么?

好吧,我想我已经确定了理论上可以安全地停止线程的条件.我还认为理论上可以静态分析线程的代码(以及它调用的方法),看看这些条件是否总是成立.但是,我不确定这是否真的很实用.

这有意义吗?我错过了什么吗?

编辑2

当你考虑到我们可能试图杀死的代码可能不受信任时,事情变得更加毛茸茸:

  1. 我们不能依赖"承诺"; 例如,对于不受信任的代码的注释,它可以是可充电的,也可以是不可投入的.

  2. 实际上,我们需要能够阻止不受信任的代码执行使其无法终止的事情......根据已确定的标准.

我怀疑这将需要修改JVM行为(例如,实现运行时限制允许锁定或修改的线程),或者完全实现Isolates JSR.这超出了我所考虑的"公平游戏"的范围.

因此,现在让我们排除不受信任的代码案例.或者至少,承认恶意代码可以做一些事情来使自己不能安全地杀戮,并把这个问题放在一边.


djn*_*jna 10

缺乏安全性来自关键部分的想法

Take mutex

do some work, temporarily while we work our state is inconsistent

// all consistent now

Release mutex
Run Code Online (Sandbox Code Playgroud)

如果你吹掉线程并且它发生在关键部分,那么该对象将处于不一致状态,这意味着从该点开始不能安全使用.

为了安全地杀死线程,您需要了解该线程中正在执行的任何操作的整个处理,以便知道代码中没有这样的关键部分.如果您使用的是库代码,那么您可能无法查看源代码并知道它是安全的.即使它今天安全,也可能不是明天.

(非常做作)可能不安全的例子.我们有一个链表,它不是循环的.所有的算法都非常活泼,因为我们知道它不是循环的.在我们的关键部分,我们暂时引入一个循环.然后,在我们从关键部分出现之前,我们会被吹走.现在所有使用列表的算法永远循环.没有图书馆作者肯定会这样做!你怎么知道的?您不能假设您使用的代码写得很好.

在您指向的示例中,肯定可以以可中断的方式编写requreid功能.更多的工作,但可能是安全的.

我将采用传单:没有文档的对象和方法子集可以在可取消的线程中使用,因为没有库作者想要做出保证.


Hav*_*ard 1

也许有一些我不知道的事情,但正如java.sun.com所说,它是不安全的,因为该线程正在处理的任何内容都有被损坏的严重风险。其他对象、连接、打开的文件...出于显而易见的原因,例如“在未先保存的情况下不要关闭 Word”。

对于这个find(...)例子,我真的不认为简单地用无用的方法将其踢开会是一场灾难.stop()......