我想在初始化map时只创建一次锁。这是我正在使用的代码。
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;
}
答案 0 :(得分: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
。)
你真的需要它比那更懒惰吗?
答案 1 :(得分:2)
几乎正确...想想一个线程检查orderStatusMap == null并获得true的情况。然后调度程序切换到执行相同检查的另一个线程。两个线程都不会执行同步块。
通过在synchronized块中另一次检查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;
是的,这样做两次都没问题。外部检查仍然有助于提高性能,因为在创建地图后,不再需要进行同步块的昂贵步骤。
请记住,这是一种创建hashmap的线程安全方法。它不会使地图成为线程安全的。
P.S。:如果你喜欢这个问题,你可能也喜欢:How to directly initialize a HashMap (in a literal way)?
答案 2 :(得分:0)
您应该对null
区块内的synchronized
进行另一次检查。
当两个线程调用您的方法时,它们都会发现orderStatusMap
为空,其中一个将进入synchronized
块,而另一个将阻塞。但最终它将在同步块内传递并再次初始化地图。
答案 3 :(得分: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;
}