I want to use the concurrent hash map holding some results,
ConcurrentHashMap<Long,AtomicInteger>
add a new entry if key not exists,or get value by key and increment,like this:
if(map.contains(key))
map.get(key).addAndGet(1);
else
map.put(key,new AtomicInteger(1));
the put operation is not thead safe,how to solve this problem? Is put operation should within synchronized block?
The ConcurrentHashMap operations are thread-safe. ConcurrentHashMap doesn't allow null for keys and values.
Concurrent. ConcurrentHashMap class achieves thread-safety by dividing the map into segments, the lock is required not for the entire object but for one segment, i.e one thread requires a lock of one segment. In ConcurrentHashap the read operation doesn't require any lock.
Having two threads that change the map at the very same point time is not possible. Because the code within that ConcurrentHashMap will not allow two threads to manipulate things in parallel!
The ConcurrentHashMap class allows multiple threads to access its entries concurrently. By default, the concurrent hashmap is divided into 16 segments. This is the reason why 16 threads are allowed to concurrently modify the map at the same time.
The put()
operation itself is implemented in a threadsafe way, i.e. if you put the same key it will be synchronized internally.
The call, however, isn't, i.e. two threads could add a new key simultaneously. You could try putIfAbsent()
and if you get a return value (i.e. not null) you could call the get method. Thus you could change your code like this:
//this only adds a new key-value pair if there's not already one for the key
if( map.putIfAbsent(key,new AtomicInteger(1)) != null ) {
map.get(key).addAndGet(1);
}
Alternatively if you're using Java 8 you could use the compute()
method which according to the JavaDoc is performed atomically. The function you pass would then check whether the value already exists or not. Since the whole call is synchronized you probably wouldn't even need to use a AtomicInteger
(depends on what else you are doing with the value).
In Java 8 you could use ConcurrentHashMap's computeIfAbsent to provide initial value:
map.computeIfAbsent(key, new AtomicInteger(0)).addAndGet(1)
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