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

2022-09-01 01:09:11

、 和 in 被弃用,因为它们不安全。Oracle 建议的解决方法是使用 ,但这种方法并非在所有情况下都有效。例如,如果调用的库方法不显式或隐式检查标志,则别无选择,只能等待调用完成。stop()suspend()resume()java.lang.ThreadThread.interrupt()interrupted

所以,我想知道是否有可能描述(可证明)调用线程是安全的情形。例如,对于除了调用或对一个线程不执行任何操作的线程来说,它是否安全?stop()stop()find(...)match(...)java.util.regex.Matcher

(如果有任何甲骨文工程师阅读本文...一个明确的答案将不胜感激。

编辑:答案只是简单地重申了你不应该称之为咒语,因为它已被弃用,不安全,无论什么都错过了这个问题的重点。我知道在大多数情况下,它确实是不安全的,如果有可行的替代方案,您应该始终使用它。stop()

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


答案 1

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

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

  1. 线程执行不得创建或改变任何状态(即 Java 对象、类变量、外部资源),这些状态在线程停止时可能对其他线程可见。
  2. 线程执行在其正常执行期间不得用于任何其他线程。notify
  3. 该线程不得或其他线程,或者与之交互然后使用 、 或 。startjoinstopsuspendresume

(上面的术语“线程执行”涵盖线程执行的所有应用程序级代码和所有库代码。

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

可停止线程必须有一种方法可以将每个计算的结果传递到控制线程。这些结果是由可停止线程创建/突变的,因此我们只需要确保它们在线程停止后不可见。例如,可以将结果分配给 Thread 对象的私有成员,并使用线程以原子方式表示“完成”的标志进行“保护”。

编辑:这些条件非常严格。例如,对于要安全停止的“正则表达式评估器”线程,如果我们必须保证正则表达式引擎不会改变任何外部可见状态。问题是它可能确实如此,这取决于你如何实现线程!

  1. 这些方法可能会更新已编译模式的静态缓存,如果它们这样做,它们将(应该)使用互斥体来执行此操作。(实际上,OpenJDK 6.0版本不会缓存Patterns,但Sun可能会改变这一点。Pattern.compile(...)
  2. 如果您尝试通过在控制线程中编译正则表达式并提供预实例化来避免 1),则正则表达式线程确实会改变外部可见状态。Matcher

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

在第二种情况下,如果 没有将 传递给其他线程,并且控制器线程在停止正则表达式匹配器线程后没有尝试使用,我们就可以了。MatcherMatcher

那么,这给我们留下了什么呢?

好吧,我想我已经确定了线程在理论上可以安全停止的条件。我还认为,从理论上讲,静态分析线程的代码(以及它调用的方法)以查看这些条件是否始终有效是可能的。但是,我不确定这是否真的实用。

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

编辑 2

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

  1. 我们不能依赖“承诺”;例如,在不受信任的代码上注释它要么是可杀死的,要么是不可杀死的。

  2. 我们实际上需要能够阻止不受信任的代码做一些会让它无法杀死的事情......根据确定的标准。

我怀疑这需要修改JVM行为(例如,实现允许锁定或修改哪些线程的运行时限制),或者隔离JSR的完整实现。这超出了我所认为的“公平游戏”的范围。

因此,让我们暂时排除不受信任的代码情况。或者至少,承认恶意代码可以做一些事情来使自己无法安全地杀死,并将这个问题放在一边。


答案 2

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

Take mutex

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

// all consistent now

Release mutex

如果您吹走了线程并且它恰好位于关键部分,则对象将处于不一致的状态,这意味着从那时起无法安全地使用。

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

(非常人为)可能的不安全因素示例。我们有一个链接列表,它不是循环的。所有的算法都非常简洁,因为我们知道它不是循环的。在我们的关键部分,我们暂时引入了一个周期。然后,在我们离开关键部分之前,我们就会被吹走。现在所有算法永远使用列表循环。没有图书馆的作者会这样做!你怎么知道?您不能假设您使用的代码写得很好。

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

我将介绍一个传单:没有可以在可取消线程中使用的对象和方法的记录子集,因为没有库作者想要做出保证。