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

标签 java multithreading

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

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/

相关文章:

java - 如何在 ant 中使用参数运行特定的 junit 测试?

c - 线程安全变量 comaprison C VS2010

c - 线程,为什么 1000 个线程和 2000 个线程没有太大明显区别

java - 我应该使用 AsyncTask 还是 IntentService 进行 REST API 调用?

java - 在 Java 8 中生成具有无限循环的线程的最佳方法是什么?

java - java中如何合并2个对象

java - GraphStream 在图中绘制分组节点

java - 如何将运行时数据注入(inject)使用 JAXB 解析 XML 时创建的对象

java - Hudson JDK 9 JAVA_HOME 看起来不像 JDK 目录

java - 动态更改提交给Executor服务的命令列表