我试图以线程安全的方式延迟初始化 map 。我在initialization-on-demand holder idiom之后提出了这个:

private static class NameIndexMapHolder {
    private static final Map<String, Long> NAME_INDEX_MAP;
    static {
        Map<String, Long> map = new HashMap<>();
        map.put("John", 3424534643);
        map.put("Jane", 4328759749);
        NAME_INDEX_MAP = Collections.unmodifiableMap(map);
    }
}

public static Map<String, Long> getNameIndexMap() {
    return NameIndexMapHolder.NAME_INDEX_MAP;
}

这行得通吗?它是线程安全的吗?从我阅读的内容来看,这仅适用于Singletons。我读过的唯一其他选择是双重检查锁定,它似乎有其自身的问题。

最佳答案

是的,这是线程安全和惰性的。

首先,让我们看一下它是否是线程安全的:

  • 两个线程可以分配对NAME_INDEX_MAP的引用吗? 编号在静态初始化程序中发生,仅在初始化类(JLS 8.7)时执行。类初始化使用同步来确保只有一个线程将执行初始化程序(JLS 12.4.2)。
  • 初始出版物安全吗? 是。 JLS实际上对此有点模糊,但是VM定义(JVMS)是明确的:

  • 发布后是否会修改对象? 编号它包装在一个不可修改的Map中,没有其他对底层可修改的HashMap的引用。

  • 那么,这是懒惰的吗?是的;仅在首次访问该类的任何成员之前立即进行类初始化(JLS 12.4.1),在这种情况下,您只有一个字段。因此,初始化只会在您第一次访问NAME_INDEX_MAP之前立即进行,这是您想要的惰性。

    10-07 19:12
    查看更多