Wednesday 14 June 2017

ConcurrentHashMap in Java

ConcurrentHashMap

ConcurrentHashMap in Java is introduced as an alternative of Hashtable in Java 1.5 as part of Java concurrency package.  Prior to Java 1.5 if you need a Map implementation, which can be safely used in a concurrent and multi-threaded Java program, then you only have Hashtable or synchronized Map because HashMap is not thread-safe.
With ConcurrentHashMap, not only it can be safely used in concurrent multi-threaded environment but also provides better performance over Hashtable and synchronizedMap. 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. ConcurrentHashMap allows concurred read operations and same time, maintains integrity by synchronizing write operations.

How ConcurrentHashMap is implemented in Java

ConcurrentHashMap provided all functions supported by Hashtable with additional feature called "concurrency level", which allows ConcurrentHashMap to partition Map. 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. This means, 16 thread can operate on Map simultaneously, until they are operating on different part of Map. This makes ConcurrentHashMap high performance despite keeping thread-safety intact. Though, it comes with warning. Since update operations like put(), remove(), putAll() or clear() is not synchronized, concurrent retrieval may not reflect most recent change on Map.
Another important point to remember is iteration over CHM, Iterator returned by keySet of ConcurrentHashMap are weekly consistent and they only reflect state of ConcurrentHashMap and certain point and may not reflect any recent change. Iterator of ConcurrentHashMap's keySet area also fail-safe and doesn’t throw ConcurrentModificationExceptoin.

ConcurrentHashMap putifAbsent example in Java

Many times we need to insert entry into Map, if it’s not present already, and we wrote following kind of code:

synchronized(map){  
  if (map.get(key) == null){  
    return map.put(key, value);  
  } else{  
    return map.get(key);  
  }  
 }  

Though this code will work fine in HashMap and Hashtable, This won't work in ConcurrentHashMap; because, during put operation whole map is not locked, and while one thread is putting value, other thread's get() call can still return null which result in one thread overriding value inserted by other thread. Of course, you can wrap whole code in synchronized block and make it thread-safe but that will only make your code single threaded. ConcurrentHashMap provides putIfAbsent(key, value) which does same thing but atomically and thus eliminates above race condition.
Eg:
public class ConcurrentHashMapTest implements Runnable {  
     private String name;  
     private static Map<String,String> conpage=new ConcurrentHashMap<String,String>();  
     ConcurrentHashMapTest(String name){  
        conpage.put("1","A");  
        conpage.put("2","B");  
        conpage.put("3","C");  
        this.name=name;  
     }  
     public void run() {  
        try{  
            Iterator<String> it = conpage.keySet().iterator();  
            while(it.hasNext()){  
               String key=it.next();  
               conpage.put("A"+key, "A"+key);  
            }  
            System.out.println(name +" completed.");  
        }catch(Exception e){  
            e.printStackTrace();  
        }  
     }  
     public static void main(String[] args) {  
        ExecutorService executor= Executors.newCachedThreadPool();  
        executor.execute(new ConcurrentHashMapTest("Thread one"));  
        Iterator<String> itt = conpage.keySet().iterator();  
        while(itt.hasNext()){  
            String key=itt.next();  
            System.out.println(conpage.get(key));  
        }  
        executor.execute(new ConcurrentHashMapTest("Thread two"));  
        Iterator<String> it = conpage.keySet().iterator();  
        while(it.hasNext()){  
            String key=it.next();  
            System.out.println(conpage.get(key));  
        }  
        executor.shutdownNow();  
     }     
 }  

Output-  
 A  
 C  
 B  
 Thread one completed.  
 A  
 A2  
 A1  
 A3  
 C  
 B  
 Thread two completed.  

When to use ConcurrentHashMap in Java

  • ConcurrentHashMap is best suited when you have multiple readers and few writers. If writers outnumber reader, or writer is equal to reader, than performance of ConcurrentHashMap effectively reduces to synchronized map or Hashtable.
  • ConcurrentHashMap is a good choice for caches, which can be initialized during application start up and later accessed my many request processing threads.
  • For those who have seen the green-box load jobs written in SpringBatch, many of the one-time populated Maps in beforeJob, whch are always read alone, are all ConcurrentHashMap ‘s.

Enjoy Learning :)

No comments:

Post a Comment