请考虑以下代码片段。
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 并发实践