简体   繁体   中英

FindBugs sequence of calls to ConcurrentHashMap may not be atomic

I do not understand why FindBug complains about this code

Foo obj = map.get(id);

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

obj.add(someObject);

Second Version

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

obj.add(someObject);

If I do second version, I have to create Foo object every time.

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);

With third version, FindBugs still complains about not atomic.

It says :

Sequence of calls to concurrenthashmap may not be atomic

Changing put to putIfAbsent , FindBugs still complains.

Findbugs observes that the pair of method invocations map.get(id) , map.put(id, obj) may not be atomic, meaning that it is possible that some other thread modifies map in between.

For example, another thread may record a different mapping for key id between those two calls, which then gets silently lost when the first thread executes its map.put() . Since you bother to test whether there is initially a mapping for that key, this result seems unlikely to be an acceptable one.

One way to approach this issue would be to use ConcurrentHashMap.putIfAbsent() in place of both calls (not just in place of put() ).

If some other thread adds an entry with that key while your thread is evaluating the if () statement, your thread will overwrite it.

You need to use putIfAbsent only , not not interact with the map otherwise.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM