java - 空引用的安全初始化
问题描述
我想知道对于初始化为 null 的非最终字段(如果有)存在哪些发布保证。
考虑以下代码段:
public class MyClass {
private final CopyOnWriteArrayList<Inner> list = new CopyOnWriteArrayList<>();
//called by thread 1
public void init() {
// initialise Inner instance
list.add(new Inner());
}
//called by thread 2
public void doSomething() {
for (Inner i : list) {
// access non-final field
Object ref = i.ref;
// do something
// ...
// ...
// potentially set i.ref
}
}
private static class Inner {
// initialised by thread 1
Object ref = null;
}
}
假设doSomething()
总是由线程 2 调用,这安全吗?对线程 2 第一次访问它时会看到什么做出了哪些保证?线程 2 是否有可能看到非空的东西?
JMM 在哪里描述了围绕这种情况的语义?
解决方案
JVM
将保证您不会凭空看到值,所以除了它之外的任何东西null
都是不可能的,以防它List
不是空的(在这个例子中,当然)。如果涉及到不同的线程(比方说Thread3
)会改变您的列表(向其中添加元素),则Thread2
可以看到这些更新。请注意,单个方法CopyOnWriteArrayList
是线程安全的;你的方法doSomething
不是。
有关详细信息,请参阅JLS或出色的(而且相当复杂,可能只是对我而言)Aleksey 文章。