Java易失性语义,JMM保证



请考虑以下代码片段。

public class Visibility {
private volatile SomeData data;
public static class SomeData {
private int number;
public SomeData(int number) {
this.number = number;
}
public int getNumber() {
return number;
}
}
public void initialize() {
data = new SomeData(42);
}
public SomeData getData() {
return data;
}
}

如果number字段是最终的,则任何看到引用data线程都不会null(在称为initialize的其他线程之后)也保证number字段值视为42

我们对非最终字段有相同的保证吗? 换句话说,某些线程是否有可能观察到非空data参考,但number字段0

提前感谢!

某些线程不可能观察到非空数据引用,而是将数字字段视为 0。

请参阅易失性文档:

这意味着对易失变量的更改始终可见 其他线程。更重要的是,这也意味着当线程读取 易失性变量,它看到的不仅仅是易变性的最新变化,还有导致更改的代码的副作用

因此,当您得到一个非空data时,它必须已成功启动,number必须为非零。

通常,是的,如果字段未以安全方式发布,则可能会看到处于部分构造状态的字段。在您的问题的特定情况下,volatile关键字是一种令人满意的安全发布形式。根据实践中的Java并发:

若要安全地发布对象,请同时引用对象和 对象的状态必须同时对其他线程可见。 正确构造的对象可以通过以下方式安全地发布:

  • 从静态初始值设定项初始化对象引用。
  • 将对它的引用存储到易失性字段中。
  • 将对它的引用存储到最后一个字段中。
  • 将对它的引用存储到由(同步)锁正确保护的字段中。

有关详细信息,请参阅以下内容:

  • 易失性引用是否真的保证对象的内部状态对其他线程可见?
  • Java 多线程和安全发布
  • Java 并发实践

最新更新