4

In a multi-threaded application, is there any scenario in which it is better to use a HashMap with synchronization when needed, than to use a ConcurrentHashMap?

Specifically, I am thinking of an application where the map is initialized like this:

Map<String,String> map = new HashMap<>();

Each thread accesses the map only to update it and immediately convert it to string, so the only synchronized block is:

synchronized(map) {
    map.put(key,value);
    StringBuilder sb = new StringBuilder();
    for (String k: map.keySet())
        sb.append("("+k+","+map.get(k)+")");
}

In this case, will it be safer to change the initialization to:

Map<String,String> map = new ConcurrentHashMap<>();

and drop the "synchronized"?

Erel Segal-Halevi
  • 33,955
  • 36
  • 114
  • 183

4 Answers4

5

The question is what is important for you from the application point of view. If you want to have a string conversion of the map synchronized with the state after the put method invocation, your code is the only solution.

If we say that a state of the map before yours synchronized block it this:

  • key1:value1
  • key2:value2

and you invoke your piece of code with

key = "key3" and value="value3"

the synchronized block ensures the string conversion will be

(key1,value1)(key2,value2)(key3,value3)

If you remove synchronized block and change map to some synchronized implementation the only synchronized part will be put itself. So the timeline of method invoke can be in some cases like:

  • Thread1 put(x,x)
  • Thread2 put(x,x)
  • Thread1 for cycle to string conversion
  • Thread2 for cycle to string conversion

So Thread1 converts incorrect state because Thread2 was fast enough to put a new entry before Thread1 invoke string conversion.

Generally synchronized implementation of any collection is useful only in cases you want methods of collection as atomic operations. If you need cooperation of more methods in the same state of collection you have to synchronize them from outside every time.

Majlanky
  • 198
  • 2
  • 9
3

The class documentation says this:

For aggregate operations such as putAll and clear, concurrent retrievals may reflect insertion or removal of only some entries. Similarly, Iterators, Spliterators and Enumerations return elements reflecting the state of the hash table at some point at or since the creation of the iterator/enumeration.

So if you care about these cases in an atomic way, external synchronization might be what u need.

And it seems you do care about this, since you do keySet(), this is not atomic, other entries might be added or removed while you are doing your for loop

Eugene
  • 117,005
  • 15
  • 201
  • 306
2

Sure. If you have a usage pattern that requires synchronization only in rare cases, then HashMap would have less overhead than a ConcurrentHashMap. This is something you'd need to measure.

Of course unless you're doing something very specific and performance intensive, it probably doesn't really matter which one you use performance-wise. However with ConcurrentHashMap you won't have to worry about performing synchronization yourself, so that's one thing less to get wrong.

A more straightforward question would be is there any reason to use Collections.synchronizedMap(new HashMap<>()) instead of ConcurrentHashMap which has been discussed in numerous places like here: ConcurrentHashMap vs Synchronized HashMap

Kayaman
  • 72,141
  • 5
  • 83
  • 121
0

Interestingly, performance of concurrentHashMap is very close to non-thread safe HashMap and much better than synchronized HasHmap. So I do not not think that synchronized HasHmap will be better in a general scenario. https://dzone.com/articles/java-7-hashmap-vs

Anurag Sharma
  • 2,409
  • 2
  • 16
  • 34