FindBugs对ConcurrentHashMap的调用序列可能不是原子的

时间:2015-04-15 18:26:37

标签: java findbugs

我不明白为什么FindBug抱怨这段代码

Foo obj = map.get(id);

if(obj == null) {
    obj = new Foo();
    map.put(id, obj);
}

obj.add(someObject);

第二版

Foo tmp = new Foo();
obj = map.putIfAbsent(id, tmp);
if (obj == null)
   obj = tmp

obj.add(someObject);

如果我做第二个版本,我每次都必须创建Foo个对象。

Foo obj = map.get(id);

if(obj == null) {
    lock.writeLock().lock();
    try {
        obj = new Foo();
        map.put(id, obj);
    }finally {
        lock.writeLock().unlock();
    }
}

obj.add(someObject);

对于第三个版本,FindBugs仍抱怨不是原子的。

它说:

  

对concurrenthashmap的调用顺序可能不是原子的

将put更改为putIfAbsent,FindBugs仍然抱怨。

2 个答案:

答案 0 :(得分:2)

Findbugs观察到这对方法调用map.get(id)map.put(id, obj)可能不是原子的,这意味着其他一些线程可能会在其间修改map

例如,另一个线程可以在这两个调用之间记录键id的不同映射,然后在第一个线程执行其map.put()时静默丢失。由于您懒得测试是否最初存在该键的映射,因此该结果似乎不太可接受。

解决此问题的一种方法是使用ConcurrentHashMap.putIfAbsent()代替两个调用(不只是代替put())。

答案 1 :(得分:0)

如果某个其他线程在您的线程正在评估if ()语句时添加了具有该键的条目,则您的线程将覆盖它。

您需要仅使用putIfAbsent ,否则不要与地图互动。