0

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

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;
}
4

4 回答 4

9

不,这是个坏主意——你返回的是一个可变的、非线程安全的映射。您还尝试实现双重检查锁定,但没有正确执行 - 与使用静态初始化相比,正确执行它更难。

我会创建一个不可变映射(使用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。)

你真的需要它比这更懒惰吗?

于 2012-05-21T17:50:51.633 回答
2

几乎是正确的......想想一个线程检查 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(以字面的方式)?

于 2012-05-21T17:54:39.777 回答
0

您应该再次检查块null内部synchronized

当两个线程调用你的方法时,它们都会发现orderStatusMapnull,其中一个会进入synchronized块,而另一个会阻塞。但最终它将在同步块内部传递并再次初始化映射。

于 2012-05-21T17:50:37.407 回答
0

不,这是不正确的

这里也不需要延迟初始化(我相信无论如何都被过度使用了),所以只需执行以下操作:

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;
}
于 2012-05-21T18:06:14.237 回答