Why do we need concurrent hashmap when hashmap and hashtable are there already? All the three collection classes have a significant difference between them, which arises from the fact that how they achieve their thread safety. Let's discuss each of them briefly
Hashmap: is not synchronized hence it is not thread-safe so it is best suitable in non-threaded environments. When multiple thread access the hashmap simultaneously then it will lead to Fail-Fast collection which means when one thread modifies the map by adding / removing the entries while another thread is iterating over it then the iterator will throw a ConcurrentModificationException.
Let's see an example below:
public class Hashmap_Synchronization {
public static void main(String[] args) {
HashMap<Integer,String>subject_code=new HashMap<Integer,String>();
subject_code.put(1,"Math");
subject_code.put(2,"Language");
subject_code.put(3,"Arts");
Iterator<Integer>it=subject_code.keySet().iterator();
while(it.hasNext())
{
Integer val=it.next();
String sub_name=subject_code.get(val);
System.out.println("The subject name for the code "+ val+" "+"is"+" "+ sub_name);
subject_code.put(4,"Science");
}
}
In the above example while iterating the subject_code hashmap I'm trying to modify the collection by adding the entry, thus it throws an exception as the hashmap is not thread-safe. To overcome this we have to synchronize the hashmap externally or use the concurrent hashmap.
Collections.SynchronizedMap:
This method creates a synchronized wrapper around the hashmap making all operations on this map thread-safe. Although the entire map itself is synchronized, in case if we are iterating the map we have to synchronize the map object which will allow one thread to access the Map at a time as the lock is in the object level. Every read-and-write operation needs to acquire a lock which will lead to significant contention and reduced performance under high-concurrency.
Let's see an example of this method:
public class Hashmap_Synchronization {
public static void main(String[] args) {
HashMap<Integer,String>subject_code=new HashMap<Integer,String>();
subject_code.put(1,"Math");
subject_code.put(2,"Language");
subject_code.put(3,"Arts");
//Using Synchronized hashmap
Map<Integer,String> sync_map=Collections.synchronizedMap(subject_code);
sync_map.put(4, "Science");
synchronized (sync_map)
{
Iterator<Entry<Integer,String>> it1=sync_map.entrySet().iterator();
while(it1.hasNext())
{
}
}
}
In the above example, we are performing insertion and iteration on the same map, and if we do both at the same time we will get a concurrent Exception so we have to use the explicit synchronization block for the iteration.
Now when performing the insertion operation this will lock the entire object so that other thread have to wait till it get completed. Once the insertion thread releases the lock, the iteration process will start by locking the object thus preventing the potential issues.
While the synchronized hashmap provides safety in multi-threaded environments, it has a performance drop because access to the synchronized hashmap is serialized, only one thread can access or modify it at a time.
HashTable: It is synchronized and thread-safe class that effirciently maps keys to values using a hash table data structure but it is not considered as a modern Java collection framework. Hashtable has a builtin synchronization which is good choice for multi multi-threaded environment but when it comes for concurrent access to data it has a concern.
Though it is thread safe but gives poor performance in multi-threading scenarios as all methods in the hashtable need to acquire a lock for every read/write operation due to this invocation on any method has to wait until another working thread on the hashtable completes its operation.
Concurrent Hashmap:
It is a part of java .util.concurrent package , and this provides the best synchronization of all the above methods . It is well suited for multi-thread environment and it has a fine locking mechanism to ensure high concurrency without compromising on data integrity. This has a tree like structure instead of linked list to enhance the performance ,it creates an array at top of it and each index of array represent a hashmap and is seperated by different segments by default it has 16 segments.
Concurrent hashmap works bit different than other methods as it acquires lock per segment which means instead of single entire object level lock it has lock mechanism on multiple segment/bucket level. So many write operations can take place at same time but on different segments.
For any write operation (put/remove/clear etc ) , it will wait until it gets lock on that segment and then it will perform its operation on that segment. Once it completes this will release the lock on that segment.
For read operations like (get,size,etc) it does not require any locks, two or more threads can read data from same or different segment at same time without blocking eachother .
public class Concurrenthashmap_concepts {
public static void main(String[] args) {
ConcurrentHashMap<Integer,String>concurrent_map=new ConcurrentHashMap<>();
concurrent_map.put(1,"Red");
concurrent_map.put(2,"Blue");
concurrent_map.put(3,"Black");
concurrent_map.forEach((key,value)->
{
System.out.println("Key:"+key+" "+"and"+" "+"value:"+value);
concurrent_map.put(4,"Green");
});
}}
In the above example , we can able to perform the read and write operation on the same map , without any external synchronization as it uses the segmented blocking .
As compared to other methods in this blog concurrent hashmap is best for its high concurrency as well as thread safety which makes it a best choice for the applications that require concurrent data access.
This blog is a continuation of my previous posts on the topic hashmap :
Thank you for taking the time to read my blog , I hope you find it helpful. Happy learning !!