繁体   English   中英

这是在静态方法中使单例映射线程安全的正确有效方法吗?

[英]Is this the correct and efficient way to make a singleton map thread safe in a static method

我只想在地图初始化时创建一次锁。 这是我正在使用的代码。

public static Map<String, String> getOrderStatusInstance() {
    if (orderStatusMap == null) {
        synchronized (Utility.class) {
            orderStatusMap = new HashMap<String, String>();

            orderStatusMap.put("Key1", "Value1");
            orderStatusMap.put("Key2", "Value2");
            orderStatusMap.put("Key3", "Value3");
            orderStatusMap.put("Key4", "Value4");
        }
    }

    return orderStatusMap;
}

不,那是个坏主意-您将返回一个可变的,非线程安全的映射。 您还尝试实现双重检查锁定,但未正确执行-与使用静态初始化相比,要使其正确无误。

我将创建一个不可变的映射(使用Guava作为首选项),理想情况下,应作为类初始化的一部分:

private static final ImmutableMap<String, String> STATUS_MAP = ImmutableMap.of(
    "Key1", "Value1",
    "Key2", "Value2",
    "Key3", "Value3",
    "Key4", "Value4");

public static ImmutableMap<String, String> getOrderStatusInstance() {
    return STATUS_MAP;
}

(对于超过5个键/值对,请使用ImmutableMap.Builder 。)

您是否真的需要比这更懒惰?

几乎是正确的...考虑一个线程检查orderStatusMap == null并变为true的情况。 然后,调度程序切换到另一个执行相同检查的线程。 没有两个线程都将执行同步块。

通过在同步块中再次检查null来防止这种情况:

if (orderStatusMap == null) {
    synchronized (Utility.class) {
        if (orderStatusMap == null) {
            Map<String, String> tmp = new HashMap<String, String>();

            tmp.put("Key1", "Value1");
            tmp.put("Key2", "Value2");
            tmp.put("Key3", "Value3");
            tmp.put("Key4", "Value4");

            orderStatusMap = tmp;
        }
    }
}
return orderStatusMap;

是的,这样做两次就可以了。 外部检查仍然有助于提高性能,因为在创建映射后,无需再执行进入同步块的昂贵步骤。

请记住,这是创建哈希图的线程安全方法。 它不会使映射成为线程安全的。

PS:如果您喜欢这个问题,您可能还会喜欢: 如何直接初始化HashMap(以字面方式)?

您应该再次检查synchronized块内是否为null

当两个线程调用您的方法时,它们都将发现orderStatusMap为null,其中一个将在synchronized块内,而另一个将在块内。 但最终它将在同步块内传递并再次初始化映射。

不,这是不正确的

没有必要在这里进行延迟初始化(我相信无论如何都应该过度使用),所以只需执行以下操作:

private static final Map<String, String> orderStatusMap;
static{
    orderStatusMap = Collections.synchronizedMap(new HashMap<String, String>());//making it thread safe
    //or use a ConcurrentHashMap

    orderStatusMap.put("Key1", "Value1");
    orderStatusMap.put("Key2", "Value2");
    orderStatusMap.put("Key3", "Value3");
    orderStatusMap.put("Key4", "Value4");
}

public static Map<String, String> getOrderStatusInstance() {
    return orderStatusMap;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM