安全初始化空引用

时间:2018-09-25 10:54:00

标签: java thread-safety java-memory-model safe-publication

我想知道对于初始化为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中在哪里描述了这种情况的语义?

2 个答案:

答案 0 :(得分:1)

JVM将确保您不会看到稀缺值,因此,除了null 不可能 List不为空的情况(当然,在此示例中)。如果涉及到另一个线程(假设Thread3)会改变您的列表(向其中添加元素),则Thread2会看到这些更新。只需注意CopyOnWriteArrayList的各个方法是线程安全的;您的方法doSomething 不是

请参阅JLS以获取详细信息或出色的文档(而且相当复杂,可能对我而言只是Aleksey article)。

答案 1 :(得分:0)

仅当您使用具有状态的有意义的对象初始化字段时,谈论安全发布才有意义。然后,发布不当可能导致观察部分构造的对象

在这种情况下,null 不传达任何状态。它可以被视为一个不变的对象。不可变的对象没有发布问题。

  

对于什么线程2首次被访问有什么保证?

线程2在引用null时将看到i.ref
请注意,该列表可能为空,因为线程1可能尚未向其添加Inner

  

线程2是否有可能看到非空的内容?

否。