如何解决findbug对java.util.concurrent.ConcurrentHashMap的调用序列可能不是原子的

时间:2014-01-21 06:51:17

标签: java findbugs java.util.concurrent concurrenthashmap

您好我在我的项目中运行查找以下代码的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);

任何人都可以帮我解决问题。

3 个答案:

答案 0 :(得分:12)

复合操作在并发环境中是不安全的。

您正在执行哪些复合操作?

  • 1)您正在检查Map是否包含密钥的向量
  • 2)如果没有找到值,您将放置一个新的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);
    }
}