您好我在我的项目中运行查找以下代码的bug时,会出现“对java.util.concurrent.ConcurrentHashMap的调用序列可能不是原子”的错误。
public static final ConcurrentHashMap<String,Vector<Person>> personTypeMap = new ConcurrentHashMap<String, Vector<Person>>();
private static void setDefaultPersonGroup() {
PersonDao crud = PersonDao.getInstance();
List<Person> personDBList = crud.retrieveAll();
for (Person person : personDBList) {
Vector<Person> personTypeCollection = personTypeMap.get(person
.getGroupId());
if (personTypeCollection == null) {
personTypeCollection = new Vector<Person>();
personTypeMap.put(personTypeCollection.getGroupId(),
personTypeCollection);
}
personTypeCollection.add(person);
}
}
我正在线上遇到问题 personTypeMap.put(personTypeCollection.getGroupId(), personTypeCollection);
任何人都可以帮我解决问题。
答案 0 :(得分:12)
您正在执行哪些复合操作?
Map
是否包含密钥的向量Vector
所以这是一个两步动作并且是复合的,所以它是不安全的。
为什么他们不安全?
因为它们 不是原子 。想想你有两个线程的场景。
考虑这个时间表:
Thread 1 --- checks for == null -> true puts a new Vector
Thread 2 --- checks for ==null -> true puts a new Vector
在putIfAbsent()
上使用ConcurrentHashMap
方法,为您提供原始解决方案。
ConcurrentHashMap#putIfAbsent()
参考文献:
答案 1 :(得分:3)
That findbugs message告诉你,在多线程访问的情况下,它并不安全:
您正在从personTypeMap
获取内容,检查它是否为null
,然后在这种情况下添加新条目。两个线程可以轻松交错:
线程1:从地图中获取
Thread2:从地图中获取
Thread1:检查null的返回值 Thread1:放新值
Thread2:检查null的返回值 线程2:放新值
(就像一个例子;实际上排序不是给定的 - 关键是线程得到null
然后对它采取行动)
您应该创建一个新条目,然后调用personTypeMap.putIfAbsent()
,因为这可以保证原子性。
答案 2 :(得分:0)
在您的情况下,您的代码应如下所示:
public static final ConcurrentHashMap<String,Vector<Person>> personTypeMap = new ConcurrentHashMap<String, Vector<Person>>();
private static void setDefaultPersonGroup() {
PersonDao crud = PersonDao.getInstance();
List<Person> personDBList = crud.retrieveAll();
for (Person person : personDBList) {
// the putIfAbsent works in the same way of your
//previous code, but in atomic way
Vector<Person> personTypeCollection = personTypeMap.putIfAbsent(person
.getGroupId());
personTypeCollection.add(person);
}
}