我有一种情况,调用者希望根据当前实例(标识符)获取bean的对象。现在,如果bean的对象存在于当前实例中,则不应再次创建它。所以有两种方法(我认为)可以做到这一点 -
1. Using putIfAbsent of ConcurrentHashMap
beanObject = objectFactory.get(); // this will create new instance every time
// even if not required
beanObject = beanMapForInstance.putIfAbsent(name, beanObject);
return beanObject;
或者
2. By Locking the map
beanObject = beanMapForInstance.get(name); // beanMapForInstance is a ConcurrentHashMap
if(beanObject == null){
synchronized (beanMapForInstance) {
beanObject = beanMapForInstance.get(name);
if(beanObject == null){
beanObject = objectFactory.getObject();
beanMapForInstance.put(name, beanObject);
}
}
}
return beanObject;
在第一种方法中,每次都会创建新对象,因此我认为第二种应该是首选。但是findbugs显示了在ConcurrentHashMap上执行同步的第二个选项的问题,那么应该使用哪个?
答案 0 :(得分:1)
在您的情况下,没有选择:您无法锁定ConcurrentHashMap
。更确切地说,锁定ConcurrentHashMap
并不像预期的那样有效。它不会使您的操作成为线程安全的,因为ConcurrentHashMap
中的线程安全操作无法通过同步对象本身来实现。
引自Javadoc of ConcurrentHashMap:
该类与依赖其线程安全但不依赖于其同步细节的程序中的Hashtable完全可互操作
如果您不想不必要地创建一个值,那么如果您使用的是JDK 8+,则可以使用computeIfAbsent
,这可以延迟实例化,直到真正需要它为止。
答案 1 :(得分:0)
如何首先检查存在,然后才将putIfAbsent?
beanObject = beanMapForInstance.get(name);
if (beanObject == null){
beanObject = beanMapForInstance.putIfAbsent(
name, objectFactory.get());
}
99.99%的时间都会工作,并且在非常罕见的竞争条件下,你会调用冗余构造函数(除了性能方面的考虑,这对你来说显然不是问题)。