I have a HashMap
ConcurrentHashMap<String, Integer> count =new ConcurrentHashMap<String, Integer>();
I will use like this:
private Integer somefunction(){
Integer order;
synchronized (this) {
if (count.containsKey(key)) {
order = count.get(key);
count.put(key, order + 1);
} else {
order = 0;
count.put(key, order + 1);
}
}
return order;
}
But as you can see, this may not be ideal to handle concurrency, since only value under the same key may interfere each other.Different key does't interfere each other so it's not necessary to synchronize all operation. I want to synchronize only when the key is the same.
Can I do something that can achieve better performance on concurrency? (I know ConcurrentHashMap and synchronize is kind of redundant here ,but let's focus on if we can only synchronize when key is same)
The whole point of ConcurrentHashMap
is to facilitate concurrent operations. Here's how you can do an atomic update with no need for explicit synchronization:
private Integer somefunction() {
Integer oldOrder;
// Insert key if it isn't already present.
oldOrder = count.putIfAbsent(key, 1);
if (oldOrder == null) {
return 0;
}
// If we get here, oldOrder holds the previous value.
// Atomically update it.
while (!count.replace(key, oldOrder, oldOrder + 1)) {
oldOrder = count.get(key);
}
return oldOrder;
}
See the Javadocs for putIfAbsent() and replace() for details.
As Tagir Valeev points out in his answer, you can use merge() instead if you're on Java 8, which would shorten the code above to:
private Integer somefunction() {
return count.merge(key, 1, Integer::sum) - 1;
}
Another option would be to let the values be AtomicInteger instead. See hemant1900's answer for how to do so.