Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java map concurrent update

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?

like image 752
MBZ Avatar asked Aug 27 '12 11:08

MBZ


2 Answers

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.

like image 164
Pavel Zdenek Avatar answered Oct 19 '22 18:10

Pavel Zdenek


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();
like image 28
Thilo Avatar answered Oct 19 '22 16:10

Thilo