Reputation: 5042
Hashtable and Collections.synchronizedMap are thread safe but still compound operations like
if (!map_obj.containsKey(key)) {
map_obj.put(key, value);
}
needs external synchronization as:
synchronized(map_obj) {
if (!map_obj.containsKey(key)) {
map_obj.put(key, value);
}
}
Suppose we have ConcurrentHashMap(CHM) instead of Hashtable or HashMap. CHM provides an alternative putIfAbsent()
method for the above compound operation, thus removing the need of external synchronization.
But suppose there is no putIfAbsent()
provided by CHM. Then can we write following code:
synchronized(concurrenthashmap_obj) {
if (!concurrenthashmap_obj.containsKey(key)) {
concurrenthashmap_obj.put(key, value);
}
}
I mean can we use external synchronization on CHM object?Will it work?
For above compound operation there is putIfAbsent()
method in CHM but how can we achieve thread safety for other compound operations if we are using CHM. I mean can we use external synchronization on CHM object?
Upvotes: 11
Views: 2016
Reputation: 7707
java.util.concurrent.ConcurrentHashMap
"is fully interoperable with Hashtable in programs that rely on its thread safety but not on its synchronization details: they do not throw ConcurrentModificationException."
"allows concurrency among update operations"
Generally speaking the reads are safe from a synchronization standpoint but not a memory standpoint.
See also "http://www.ibm.com/developerworks/java/library/j-jtp03304/".
So synchronizaton
and volatile
should be used to manage concurrent reading (vs. writing).
putIfAbsent
is your friend:
If the specified key is not already associated with a value, associate it with the given
value. This is equivalent to if (!map.containsKey(key)) return map.put(key, value); else return map.get(key);
except that the action is performed !!!atomically!!!.
Upvotes: -1
Reputation: 242686
No, you cannot use external synchronization to ensure atomicity of compound operations over ConcurrentHashMap
.
To be precise, you can use external synchronization to ensure atomicity of compound operations, but only if all operations with ConcurrentHashMap
are synchronized over the same lock as well (though use of ConcurrentHashMap
won't make sense in this case - you can replace it with regular HashMap
).
Approach with external synchronization works with Hashtable
and Collections.synchronizedMap()
only because they guarantee that their primitive operations are synchronized
over these objects as well. Since ConcurrentHashMap
doesn't provide such a guarantee, primitive operations may interfere with execution of your compound operations, breaking their atomicity.
However, ConcurrentHashMap
provides number of methods that can be used to implement compound operations in optimistic manner:
putIfAbsent(key, value)
remove(key, value)
replace(key, value)
replace(key, oldValue, newValue)
You can use these operation to implement certain compound operations without explict synchronization, the same way as you would do for AtomicReference
, etc.
Upvotes: 17
Reputation: 691685
It all depends on what you mean by "other compound operation" and by "working". Synchronization works with ConcurrentHashMap exactly the same way as it works with any other object.
So, if you want some complex shared state change to be seen as an atomic change, then all accesses to this shared state must be synchronized, on the same lock. This lock could be the Map itself, or it could be another object.
Upvotes: 1
Reputation: 311163
You can always use a synchronized
block. The fancy collections in java.util.concurrent
do not prohibit it, they just make it redundant for most common use cases. If you are performing a compound operation (e.g. - you want to insert two keys which must always have the same value), not only can you use external synchronization - you must.
E.g.:
String key1 = getKeyFromSomewhere();
String key2 = getKeyFromSomewhereElse();
String value = getValue();
// We want to put two pairs in the map - [key1, value] and [key2, value]
// and be sure that in any point in time both key1 and key2 have the same
// value
synchronized(concurrenthashmap_obj) {
concurrenthashmap_obj.put(key1, value);
// without external syncronoziation, key1's value may have already been
// overwritten from a different thread!
concurrenthashmap_obj.put(key2, value);
}
Upvotes: 6
Reputation: 14259
As the ConcurrentHashMap implements the Map Interface, it does support all features every basic Map does as well. So yes: you can use it like any other map and ignore all the extra features. But then you will essentially have a slower HashMap.
The main difference between a synchronized Map and a concurrent Map is - as the name says - concurrency. Imagine you have 100 threads wanting to read from the Map, if you synchronize
you block out 99 threads and 1 can do the work. If you use concurrency 100 threads can work at the same time.
Now if you think about the actual reason why you use threads, you soon come to the conclusion that you should get rid of every possible synchronized
block that you can.
Upvotes: 3
Reputation: 8405
There isn't any reason why you can't. Traditional synchronization works with everything, there aren't special exceptions against them. ConcurrentHashMaps simply use more optimized thread-safety mechanisms, if you wish to do something more complex, falling back to traditional synchronization may actually be your only option (that and using locks).
Upvotes: 6