Search code examples
javaconcurrencyjava-8concurrenthashmapatomic

I want to have both computeIfPresent and putIfAbsent into one atomic function


workObjectMap.computeIfPresent(key, (k,v) -> {
    v.memberIdSet.addAll(memberIdSet);
    v.memberPositionSet.addAll(memberPositionSet);
    return v;
});
// If it.remove() in run() is called at this point,
// there is a risk of the same work being done twice
workObjectMap.putIfAbsent(key, new WorkObjectValue(memberIdSet, memberPositionSet));

I have the above code. In a separate thread I may be removing from the workObjectMap. I want an atomic function that modifies the value if the key is present, and if its not, it puts the key/value.

In my current code, there is a chance that the remove will happen in between the computeIfPresent and putIfAbsent so that the same item that was already added to the map, would be added again.

How do I block any removes in between these 2 method calls? (computeIfPresent and putIfAbsent)


Solution

  • Use Map.compute():

    workObjectMap.compute(key, (k,v) -> {
        if (v == null) return new WorkObjectValue(memberIdSet, memberPositionSet);
        v.memberIdSet.addAll(memberIdSet);
        v.memberPositionSet.addAll(memberPositionSet);
        return v;
    });
    

    Note that the ConcurrentHashMap Javadoc explicitly states that this is atomic.