Java – The ConcurrentHashMap Class Tutorial


ConcurrentHashMap is a concurrent Collection class introduced in Java 5 Concurrency API. ConcurrentHashMap implements Map interface like, HashMap and Hashtable but it is thread-safe collection and it achieves its thread-safety in a slightly different way than Hashtable and other thread-safe Collection class. As ConcurrentHashMap allows concurred read operations and same time, maintains integrity by synchronizing write operations.ConcurrentHashMap performs better than earlier two because it only locks a portion of Map, instead of whole Map, which is the case with Hashtable and synchronized Map. HashMap class is fail-fast which means that if the HashMap will be changed while some thread is traversing over it using iterator, the iterator.next() will throw a ConcurrentModificationException. But Iterator of ConcurrentHashMap is fail-safe and doesn't throw ConcurrentModificationException even if underlying ConcurrentHashMap is modified once Iteration begins. Consequently all the updates made on ConcurrentHashMap is not available to Iterator. Let have a simple Example on HashMap ConcurrentModificationException:

package com.cs.map;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class HashMapIterator {
    public static void main(String[] args){
        Map myMap = new HashMap();

        myMap.put("1", "1");
        myMap.put("2", "2");
        myMap.put("3", "3");

        Iterator it1 = myMap.keySet().iterator();
        while(it1.hasNext()){
            String key = it1.next();
            System.out.println("Map Value:"+myMap.get(key));
            if(key.equals("2")){
                myMap.put("1","4");
                //myMap.put("4", "4");
            }
        }
    }
}

In the above example if we uncomment you will get an exception saying the following:

Map Value:3
Exception in thread "main" java.util.ConcurrentModificationException
Map Value:2
        at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
        at java.util.HashMap$KeyIterator.next(HashMap.java:828)
        at com.i3soft.list.HashMapIterator.main(HashMapIterator.java:17)
Java Result: 1

Since we are updating the size of the map, its size has not been changed and we are updating the value of the existing element we are not getting ConcurrentModificationException. If we add new element or removing an element from the map the Iterator throws ConcurrentModificationException.

To Avoid ConcurrentModificationException in multi-threaded environment:

  1. You can lock the Map while iterating by putting it in a synchronized block. This approach is not recommended because it will cease the benefits of multithreading.
  2. If you are using JDK1.5 or higher then you can use ConcurrentHashMap class. It is the recommended approach.

Difference between ConcurrentHashMap and HashMap:

  1. The main difference between these two is, ConcurrentHashMap is achieves thread-safe Collectiopn and it can be used in multi-threaded environment. The ArrayList is not thread-safe and can not be used in multi-threaded environment.
  2. HashMap class is fail-fast which means that if the HashMap will be changed while some thread is traversing over it using iterator, the iterator.next() will throw a ConcurrentModificationException. But Iterator of ConcurrentHashMap is fail-safe and doesn't throw ConcurrentModificationException even if underlying ConcurrentHashMap is modified once Iteration begins.
  3. The Iterator of HashMap supports remove() operation while ConcurrentHashMap does not support remove operation, if you do the ConcurrentHashMap throws UnsupportedOperationException.

Here is the complete code example of the ConcurrentHashMap:


package com.cs.list;

import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapIterator {

    public static void main(String[] args) {
        ConcurrentHashMap myMap = new ConcurrentHashMap();
        myMap.put("1", "One");
        myMap.put("2", "Two");
        myMap.put("3", "Three");
        myMap.put("4", "Four");
        myMap.put("5", "Five");

        Iterator it = myMap.keySet().iterator();
        while (it.hasNext()) {
            String key = it.next();
            if (key.equals("3")) {
                myMap.put("6", "Six");
            }
        }
    }
}

In the above code, we are not getting ConcurrentModificationException, because ConcurrentHashMap allows multiple readers to read concurrently without any blocking. This is achieved by partitioning Map into different parts based on concurrency level and locking only a portion of Map during updates. Default concurrency level is 16, and accordingly Map is divided into 16 part and each part is goverened with different lock. This means, 16 thread can operate on Map simulteneously, until they are operating on different part of Map. This makes ConcurrentHashMap high performant despite keeping thread-safety intact.

Note:

HashMap contains a variable to count the number of modifications and iterator use it when you call its next() function to get the next entry.

transient volatile int modCount;

No comments

Powered by Blogger.