请考虑以下代码段。
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
字段为final,则任何看到data
引用的线程不是null
(在称为initialize
的其他线程之后)也保证会看到{{1} }字段值为number
。
我们对非最终领域有同样的保证吗?
换句话说,某些线程是否有可能观察到非null
42
引用,data
字段为number
?
提前致谢!
答案 0 :(得分:2)
某些线程观察到非空数据引用可能不,但数字字段为0。
请参阅volatile的doc:
这意味着对volatile变量的更改始终可见 其他线程。更重要的是,它还意味着当线程读取时 volatile变量,它不仅看到了volatile的最新变化, 以及导致更改的代码的副作用。
因此,当您获得非空data
时,它必须已成功启动,number
必须为非零。
答案 1 :(得分:1)
通常,是的,如果字段未以安全方式发布,则可以看到处于部分构造状态的字段。在您的问题的特定情况下,volatile
关键字是一种令人满意的安全发布形式。根据{{3}}:
安全地发布对象,包括对象的引用和 必须同时使对象的状态对其他线程可见。 正确构造的对象可以通过以下方式安全地发布:
- 从静态初始值设定项初始化对象引用。
- 将对它的引用存储到volatile字段中。
- 将对它的引用存储到最终字段中。
- 将对它的引用存储到由(同步)锁定正确保护的字段中。
有关详细信息,请参阅以下内容: