a Learner
a Learner

Reputation: 5042

ConcurrentHashMap and compound operations

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

Answers (6)

venergiac
venergiac

Reputation: 7707

About 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"

About java memory

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).

About putIfAbsent

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

axtavt
axtavt

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

JB Nizet
JB Nizet

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

Mureinik
Mureinik

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

TwoThe
TwoThe

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

initramfs
initramfs

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

Related Questions