J Doe
J Doe

Reputation: 11

ConcurrentHashMap and operations that span 2 separate calls

I understand that ConcurrentHashMap methods are thread safe but what about compound operations that are not atomic for example see this piece of code - if 2 different threads call it at the same time with the same “myKey” isn’t it possible for a race condition to occur?

myMap is a ConcurrentHashMap

myValues = myMap.get(myKey);
if (myValues == null) {
    myValues = new List()
    myMap.add(myKey, myValues);
}
myValue.add(new list item);

How do I write the above in a thread safe way with just ConcurrentHashMap & without using separate Locks etc,

putIfAbsent does not seem to solve the issue either or is something like this feasible:

myValues =  myMap.putIfAbsent(myKey, new List());
myValues.add(new list item);

Is this correct and thread safe?
Thanks

Upvotes: 1

Views: 172

Answers (1)

Michał Ziober
Michał Ziober

Reputation: 38665

Use computeIfAbsent which is atomic:

Documentation:

If the specified key is not already associated with a value, attempts to compute its value using the given mapping function and enters it into this map unless null. The entire method invocation is performed atomically, so the function is applied at most once per key. Some attempted update operations on this map by other threads may be blocked while computation is in progress, so the computation should be short and simple, and must not attempt to update any other mappings of this map.

Simple usage:

ConcurrentHashMap<String, List<String>> map = new ConcurrentHashMap<>();
List<String> list = map.computeIfAbsent("myKey", key -> new CopyOnWriteArrayList<>());

Edit
As @Holger properly noticed ArrayList is not safe to use in this case. Much safer is using CopyOnWriteArrayList which is a thread-safe variant of ArrayList.

Upvotes: 2

Related Questions