Java并发 - 内联初始化非最终字段和安全发布

时间:2017-06-22 13:25:02

标签: java multithreading concurrency java-memory-model

假设我有以下课程:

public abstract class Test {
    private List<String> strings = new ArrayList<>();

    // to be called concurrently
    public int getStringsSize() {
        return strings.size();
    }
}

getStringsSize()是否有可能为Test的某些子类抛出NPE?或者还有什么可能出错?据我所知,没有Java内存模型可以保证这种情况。

3 个答案:

答案 0 :(得分:2)

重点是:当子类对象被实例化时,超级构造函数和超级字段init 语句将在执行任何子类代码之前执行。有关详细信息,请参阅herethere。换句话说:在通过new创建子类的客户端获取对新创建的对象的访问之前,保证执行这些init语句。

正如我们所讨论的仅存在于超类中的单个私有字段一样,该方法调用无法生成NPE

除非您有其他方法将字段重置为null。您可以通过对该字段使用最终关键字来避免这种情况(这仍然是一种很好的做法:将其设为默认以将最终放在字段上)

最后;为了完整性:有可能编写在子类上执行new时失败的超级/子类代码,因为“尚未初始化的东西” - 就像你的超类构造函数调用重写的方法在子类中。但这就像:糟糕的做法(因为它可能会导致这种奇怪的错误)。所以,甚至不要考虑这样做。

答案 1 :(得分:1)

没有。只要<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <input type="text" id="a" class="test"> <input type="text" id="b" class="test"> <input type="text" id="c" class="test"> <button type="button">Click me</button>字段没有被重新分配(由于它是私有的,它永远不能由子类完成),所以无论有多少线程尝试访问它,它都永远不会在空状态下被访问。因此,strings永远不会抛出strings.size()

答案 2 :(得分:1)

如果您在getStringSize()方法中手动将strings设置为null,则{p> setStrings()只会抛出NPE。 getStringSize()也应设置为final

初始化程序在实例化时运行,即在super(...)构造函数之后,但在this(...)构造函数的第一条指令之前运行。