I'm trying to create a Map
with int
values and increase them by multiple threads. two or more threads might increase the same key.
ConcurrentHashMap
documentation was very unclear to me since it sais that:
Retrieval operations (including get) generally do not block, so may overlap with update operations (including put and remove)
I wonder if the following code using ConcurrentHashMap
will works correctly:
myMap.put(X, myMap.get(X) + 1);
if not, how can I manage such thing?
Concurrent map will not help thread safety of your code. You still can get race condition:
Thread-1: x = 1, get(x)
Thread-2: x = 1, get(x)
Thread-1: put(x + 1) => 2
Thread-2: put(x + 1) => 2
Two increments happened, but you still get only +1. You need a concurrent map only if you aim for modifying the map itself, not its content. Even the simplest HashMap is threadsafe for concurrent reads, given the map is not mutated anymore.
So instead of a threadsafe map for primitive type, you need a threadsafe wrapper for the type. Either something from java.util.concurrent.atomic
or roll your own locked container if needing an arbitrary type.
One idea would be combining ConcurrentMap with AtomicInteger, which has a increment method.
AtomicInteger current = map.putIfAbsent(key, new AtomicInteger(1));
int newValue = current == null ? 1 :current.incrementAndGet();
or (more efficiently, thanks @Keppil) with an extra code guard to avoid unnecessary object creation:
AtomicInteger current = map.get(key);
if (current == null){
current = map.putIfAbsent(key, new AtomicInteger(1));
}
int newValue = current == null ? 1 : current.incrementAndGet();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With