ConcurrentHashMap class

In this article, we will discuss ConcurrentHashMap class – the implementation class for ConcurrentMap interface in detail

 

ConcurrentHashMap:

  • ConcurrentHashMap is the implementation class of ConcurrentMap interface (i.e.; ConcurrentHashMap implements ConcurrentMap)
  • ConcurrentHashMap uses hash table data structure to store key-value pairs (which is known as map entry)
  • Allows only unique keys and there is no such restriction on values
  • NULL insertion isn’t allowed for both key and values
  • Allows concurrent access of read and update operations (i.e.; 2 or more threads can operate on same ConcurrentHashMap object simultaneously)
  • For read operation, lock isn’t required
  • But for update operation, lock is required but that’s only for part of the Map object (i.e.; Bucket level locking)
  • Actually, bucket is divided into n-number of parts and one lock is associated with each part
  • These locks are referred as concurrency-level
  • ConcurrentHashMap never throws ConcurrentModificationException while 2 or more threads operating simultaneously
  • Present in java.util.concurrent package and extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap interface
  • Also, implements java.io.Serializable marker interfaces which provides special ability to ConcurrentHashMap (provided by JVM at run time) like,
  • java.io.Serializable: to transfer objects across network

3-concurrenthashmap-in-java Source: Team BenchResources.Net

 

ConcurrentHashMap constructors:

ConcurrentHashMap chm = new ConcurrentHashMap();

  • creates an empty ConcurrentHashMap object of size 16
  • with default fill ratio of 0.75 and default concurrency level 16

ConcurrentHashMap chs = new ConcurrentHashMap(int initialCapacity);

  • creates an empty ConcurrentHashMap object of specified size or initial capacity
  • with default fill ratio 0.75 and default concurrency level 16

ConcurrentHashMap chs = new ConcurrentHashMap(int initialCapacity, float loadFactor);

  • creates an empty ConcurrentHashMap object of specified size or initial capacity
  • with specified fill ratio (for example 0.85) and default concurrency level 16

ConcurrentHashMap chs = new ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel);

  • creates an empty ConcurrentHashMap object of specified size or initial capacity
  • with specified fill ratio (for example 0.85) and specified concurrency level (for example 11)

ConcurrentHashMap chs = new ConcurrentHashMap(Map m);

  • creates an equivalent ConcurrentHashMap object for the specified map
  • it is basically used for inter-conversion between map objects

 

Fill ratio (or Load factor) :

  • Fill ratio is also known as Load factor
  • This factor determines when to increase the size of LinkedHashMap automatically
  • For example, for the 1st two constructors the default load factor is 75 –> which means after filling 75 % of HashMap, new HashMap of bigger size will be created
  • For 3rd constructor, programmer can define load factor while creating HashMap object. If programmer define it to be 0.95, then after filling 95% of HashMap, size of HashMap will be increased automatically

 

ConcurrentHashMap example:

ConcurrentHashMapPutRemoveAndReplace.java

package in.bench.resources.concurrent.collection;

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

public class ConcurrentHashMapPutRemoveAndReplace {

	public static void main(String[] args) {

		// creating ConcurrentHashMap object of type <Integer, String>
		ConcurrentHashMap<Integer, String> chm = 
				new ConcurrentHashMap<Integer, String>();

		// adding key-value pairs to ConcurrentHashMap object
		chm.put(1, "google.com");
		chm.put(2, "youtube.com");
		chm.put(3, "facebook.com");

		// adding key-value pairs using ConcurrentMap method
		chm.putIfAbsent(5, "yahoo.com"); // 1st
		chm.putIfAbsent(7, "wikipedia.com"); // 2nd

		// not-inserted, as key is already present
		chm.putIfAbsent(1, "baidu.com"); // 3rd

		System.out.println("Iterating before remove and replace\n");

		// iterating using enhanced for-loop
		for(Map.Entry<Integer, String> me : chm.entrySet()) {
			System.out.println("Rank : "  + me.getKey() + "\t" 
					+ "Website : "  + me.getValue());
		}

		// removing: both key & value should match
		chm.remove(5, "yahoo.com");

		System.out.println("\n\nIterating after remove(5, yahoo.com)\n");

		// iterating using enhanced for-loop
		for(Map.Entry<Integer, String> me : chm.entrySet()) {
			System.out.println("Rank : "  + me.getKey() + "\t" 
					+ "Website : "  + me.getValue());
		}

		// replacing: both key & value should match
		chm.replace(2, "youtube.com", "amazon.com");

		System.out.println("\n\nIterating after "
				+ "replace(2, youtube.com, amazon.com)\n");

		// iterating using enhanced for-loop
		for(Map.Entry<Integer, String> me : chm.entrySet()) {
			System.out.println("Rank : "  + me.getKey() + "\t" 
					+ "Website : "  + me.getValue());
		}
	}
}

Output:

Iterating before remove and replace

Rank : 2	Website : youtube.com
Rank : 1	Website : google.com
Rank : 5	Website : yahoo.com
Rank : 7	Website : wikipedia.com
Rank : 3	Website : facebook.com


Iterating after remove(5, yahoo.com)

Rank : 2	Website : youtube.com
Rank : 1	Website : google.com
Rank : 7	Website : wikipedia.com
Rank : 3	Website : facebook.com


Iterating after replace(2, youtube.com, amazon.com)

Rank : 2	Website : amazon.com
Rank : 1	Website : google.com
Rank : 7	Website : wikipedia.com
Rank : 3	Website : facebook.com

Explanation:

  • When normal put() method is used to insert key-value pairs, then all entries inserted successfully
  • But when putIfAbsent() method of ConcurrentMap is used, then key-value pair is inserted only when key isn’t already present inside ConcurrentHashMap (check comments 1st, 2nd and 3rd)
  • As an example in the above case, 1-baidu.com isn’t inserted because 1-google.com is already present in the ConcurrentHashMap
  • Similarly, when we use remove(5, yahoo.com) –> this is removed from ConcurrentHashMap only when both key-value pair is present
  • Otherwise, no effects take place in the invoking Map
  • Likewise, replace(2, youtube.com, amazon.com) method –> 2nd parameter is replaced by 3rd parameter only when matching key-value pair is present in the invoking Map
  • Otherwise, no effect take place in the invoking Map

 

Modification while Iterating:

  • entrySet() method returns set view of map entries
  • Iterating ConcurrentHashMap using Iterator interface or enhanced for-loop guarantees that it runs through all entries
  • But doesn’t guarantees any modification to iterating map entries
  • So, while iterating map entries either we get updated entries or else entries before updation
  • See below for Java doc statement highlighted in RED
  • Java doc for ConcurrentHashMap in 1.7 version

3a-concurrenthashmap-iterator-in-java

 

References:

 

Happy Coding !!
Happy Learning !!

ConcurrentHashMap with Read and Update operations simultaneously
ConcurrentMap interface