gpt4 book ai didi

设置对象引用的 Java 线程安全性

转载 作者:行者123 更新时间:2023-11-30 02:18:56 25 4
gpt4 key购买 nike

我想知道以下类是否是线程安全的:

class Example {

private Thing thing;

public setThing(Thing thing) {
this.thing = thing;
}

public use() {
thing.function();
}
}

具体来说,如果一个线程调用 setThing,而另一个线程通过 Example::use 处于 Thing::function 中,会发生什么?

例如:

Example example = new Example();
example.setThing(new Thing());

createThread(example); // create first thread
createThread(example); // create second thread
<小时/>
//Thread1
while(1) {
example.use();
}
<小时/>
//Thread2
while(1) {
sleep(3600000); //yes, i know to use a scheduled thread executor
setThing(new Thing());
}

具体来说,我想知道,当 use() 执行时调用 setThing 时,它是否会成功地继续使用旧对象,或者更新对对象的引用会以某种方式导致问题。

最佳答案

在推理特定类的线程安全性时有两点:

  1. 线程之间共享状态的可见性。
  2. 多线程通过类方法使用类对象时的安全性(保留类不变量)。

Example 类的共享状态仅由一个 Thing 对象组成。

  1. 从可见性的角度来看,该类不是线程安全的。一个线程的 setThing 结果不会被其他线程看到,因此它们可以使用过时的数据。 NPE 也是可以接受的,因为类初始化期间 thing 的初始值为 null
  2. 无法确定在没有源代码的情况下通过 use 方法访问 Thing 类是否安全。但是 Example 调用 use 方法时没有任何同步,所以它应该是这样,否则 Example 不是线程安全的。

因此示例不是线程安全的。要修复第 1 点,如果您确实需要 setter,可以将 volatile 添加到 thing 字段,或者将其标记为 Final 并在构造函数中初始化。确保满足 2 的最简单方法是将 use 标记为 synchronized。如果您将 setThing 标记为 synchronized,那么您就不再需要 volatile 了。然而,还有许多其他复杂的技术可以满足第 2 点。 This伟大的书更详细地描述了这里写的所有内容。

关于设置对象引用的 Java 线程安全性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47424947/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com