我想知道对于初始化为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中在哪里描述了这种情况的语义?
答案 0 :(得分:1)
JVM
将确保您不会看到稀缺值,因此,除了null
不可能 List
不为空的情况(当然,在此示例中)。如果涉及到另一个线程(假设Thread3
)会改变您的列表(向其中添加元素),则Thread2
会看到这些更新。只需注意CopyOnWriteArrayList
的各个方法是线程安全的;您的方法doSomething
不是。
请参阅JLS以获取详细信息或出色的文档(而且相当复杂,可能对我而言只是Aleksey article)。
答案 1 :(得分:0)
仅当您使用具有状态的有意义的对象初始化字段时,谈论安全发布才有意义。然后,发布不当可能导致观察部分构造的对象。
在这种情况下,null
不传达任何状态。它可以被视为一个不变的对象。不可变的对象没有发布问题。
对于什么线程2首次被访问有什么保证?
线程2在引用null
时将看到i.ref
。
请注意,该列表可能为空,因为线程1可能尚未向其添加Inner
。
线程2是否有可能看到非空的内容?
否。