Java ConcurrentHashMap Working | JavaInUse



Understanding the Java ConcurrentHashMap



What is Concurrent HashMap in Java

The ConcurrentHashMap class provides a concurrent version of the standard HashMap. So its functionality is similar to a HashMap, except that it has internally maintained concurrency. Depending upon the level of concurrency required the concurrent HashMap is internally divided into segments. If the level of concurrency required is not specified then it is takes 16 as the default value. So internally the ConcurrentHashMap will be divided into 16 segments. Each Segment behaves independently. We will take a look at the segments in the below examples.

Class Hierarchy
java.lang.Object
java.util.AbstractMap<K,V>
java.util.concurrent.ConcurrentHashMap<K,V>

Type Parameters:
K - the type of keys maintained by this map
V - the type of mapped values
All Implemented Interfaces: Serializable, ConcurrentMap<K,V>, Map<K,V>

public ConcurrentHashMap()-
Creates a new, empty map with a default initial capacity (16), load factor (0.75) and concurrencyLevel (16).

Video

This tutorial is explained in the below Youtube Video.

Why use Concurrent Hashmap-

We use ConcurrentHashMap when a high level of concurrency is required. But already SynchronizedMap is present so what advantages does ConcurrentHashMap have over synchronized map.Both are thread safe. The major advantage is in case of synchronizedMap every write operation acquires lock on entire SynchronizedMap while in case of ConcurrentHashMap the lock is only on one of the segments.

SynchronizedMap-

ConcurrentHashMap-

Lets see how synchronizedMap behaves in a multithreaded environment.
Create a class which implements Runnable class takes instance of Map and insert value in it.
package com.javainuse.helper;

import java.util.Map;

public class MapHelper1 implements Runnable {
	Map<String, Integer> map;

	public MapHelper1(Map<String, Integer> map) {
		this.map = map;
		new Thread(this, "MapHelper1").start();
	}

	public void run() {
		map.put("One", 1);
		try {
			System.out.println("MapHelper1 sleeping");
			Thread.sleep(100);
		} catch (Exception e) {
			System.out.println(e);
		}

	}
}
Create multiple such runnable classes MapHelper2,MapHelper3,MapHelper4.
Now we will create an instance of SynchronizedMap and test it as follows-
package com.javainuse.main;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import com.javainuse.helper.MapHelper1;
import com.javainuse.helper.MapHelper2;
import com.javainuse.helper.MapHelper3;
import com.javainuse.helper.MapHelper4;

public class MainClass {

	public static void main(String[] args) {
		Map<String, Integer> hashMap = new HashMap<>();
		Map<String, Integer> syncMap = Collections.synchronizedMap(hashMap);
		MapHelper1 mapHelper1 = new MapHelper1(syncMap);
		MapHelper2 mapHelper2 = new MapHelper2(syncMap);
		MapHelper3 mapHelper3 = new MapHelper3(syncMap);
		MapHelper4 mapHelper4 = new MapHelper4(syncMap);

		for (Map.Entry<String, Integer> e : syncMap.entrySet()) {
			System.out.println(e.getKey() + "=" + e.getValue());
		}

	}

}
On running the above example we get an exception as follows-

We get this exception because the while reading the contents of the SynchronizedMap, it is modified by other thread. Now lets see the behaviour of ConcurrentHashMap.
package com.javainuse.main;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.javainuse.helper.MapHelper1;
import com.javainuse.helper.MapHelper2;
import com.javainuse.helper.MapHelper3;
import com.javainuse.helper.MapHelper4;

public class MainClass {

	public static void main(String[] args) {
		Map<String, Integer> conMap = new ConcurrentHashMap<>();
		MapHelper1 mapHelper1 = new MapHelper1(conMap);
		MapHelper2 mapHelper2 = new MapHelper2(conMap);
		MapHelper3 mapHelper3 = new MapHelper3(conMap);
		MapHelper4 mapHelper4 = new MapHelper4(conMap);

		for (Map.Entry<String, Integer> e : conMap.entrySet()) {
			System.out.println(e.getKey() + "=" + e.getValue());
		}

	}

}
Get the output as-

In case of Concurrent Map even if map is changed while iterating it, no exception is thrown.

Internal Working of ConcurrentHashMap-

As no concurrency level has been set explictity, the ConcurrentHashMap gets divided into 16 segments. And each segment acts as an independent HashMap. During right operation the Lock is obtained on this particular segment and not on the entire HashMap Debug the code when it reaches the for Loop above and check the conMap details-


As you can see the table contains the 16 segments. Out of these only three are populated and remaining are null. As soon as new value is to be inserted a new segment will then be populated. (In previous versions of java, whether populated or not all the sixteen segments would get initialized, but this has been improved)

Difference between ConcurrentHashMap and SynchronizedMap -

The major differences are-
SynchronizedHashMap ConcurrentHashMap
Synchronization is at Object level Synchronization is at segment level
A lock is obtained for read/write operation at object level A lock is obtained for write operation at segment level
Concurrency level cannot be set for better optimization Concurrency level can be set for better optimization
ConcurrentModification Exception is thrown if a thread tries to modify an existing SynchronizedMap which is being iterated ConcurrentModification Exception is thrown if a thread tries to modify an existing ConcurrentHashMap which is being iterated
Since at a given time only a single Thread can modify the map and block other threads the performance is comparatively bad. Multiple Threads can modify ConcurrentHashMap. Hence performance is much better.

Download Source Code

Download it - Concurrent HashMap Example
Synchronized HashMap Example

See Also

Overriding equals() in Java Image Comparison in Java Java - PermGen space vs Heap space Java - PermGen space vs MetaSpace Implement Counting Sort using Java + Performance Analysis Java 8 Features Java Miscelleneous Topics Java Basic Topics Java- Main Menu