HashMap
is a very powerful data structure in Java. We use it everyday and almost in all applications. There is quite a few examples which I had written before on what to Implement Threadsafe cache, how to convert Hashmap to Arraylist?
We used Hashmap in both above examples but those is pretty simple use cases of Hashmap. HashMap is a non-synchronized
Collection class.
Does any of the below questions?
- What ' s the difference between Concurrenthashmap and Collections.synchronizedmap (MAP)?
- What's the difference between Concurrenthashmap and Collections.synchronizedmap (MAP) in the term of performance?
- Concurrenthashmap vs Collections.synchronizedmap ()
- Popular HashMap and Concurrenthashmap interview questions
In this tutorial we'll go over all above queries and reason why and how
we could Synchronize Hashmap?
Why?
The Map object is an associative containers that store elements, formed by a combination of a uniquely identify and key
A mapped value
. If you had very highly concurrent application in which you could want to modify or read key value in different threads then It ' s ideal to use Concurrent Hashmap. Best example is Producer Consumer which handles concurrent read/write.
So what does the Thread-safe Map means? If multiple threads
access a hash map concurrently, and at least one of the threads modifies the map structurally, it to must be synchronized externally
avoid a n Inconsistent view of the contents.
How?
There is ways we could synchronized HashMap
- Java Collections Synchronizedmap () method
- Use Concurrenthashmap
HashMap vs. Synchronizedmap vs. Concurrenthashmap
// Hashtable New Hashtable<string, string>//synchronizedmapsynchronizedhashmap = Collections.synchronizedmap (new hashmap<string, string>// ConcurrenthashmapNew concurrenthashmap<string, string> ();
Concurrenthashmap
- You should use Concurrenthashmap if you are need very high concurrency in your project.
- It is the thread safe without synchronizing the whole map.
- Reads can happen very fast while write is do with a lock.
- There is no locking on the object level.
- The locking is at a much finer granularity at a hashmap buckets level.
- Concurrenthashmap doesn ' t throw a
ConcurrentModificationException
if one thread tries to modify it while another was iterating over it.
- Concurrenthashmap uses multitude of locks.
Synchronizedhashmap
- Synchronization at Object level.
- Every read/write operation needs to acquire lock.
- Locking the entire collection is a performance overhead.
- This essentially gives access to only one thread to the entire maps & blocks all of the other threads.
- It may cause contention.
- Synchronizedhashmap returns Iterator, which fails-fast on concurrent modification.
Now let's take a look at code
- Create class
CrunchifyConcurrentHashMapVsSynchronizedHashMap.java
- Create object for each HashTable, Synchronizedmap and Crunchifyconcurrenthashmap
- ADD and retrieve 500k entries from Map
- Measure start and end time and display time in milliseconds
- We'll use Executorservice to run 5 threads in parallel
Crunchifyconcurrenthashmapvssynchronizedmap.javaJava
Package crunchify.com.tutorials; import Java.util.collections;import Java.util.hashmap;import Java.util.hashtable;import Java.util.map;import Java.util.concurrent.concurrenthashmap;import Java.util.concurrent.executorservice;import Java.util.concurrent.executors;import Java.util.concurrent.TimeUnit; /** * @author crunchify.com**/ Public classCrunchifyconcurrenthashmapvssynchronizedmap { PublicFinalStatic intThread_pool_size =5; Public Staticmap<string, integer> crunchifyhashtableobject =NULL; Public Staticmap<string, integer> crunchifysynchronizedmapobject =NULL; Public Staticmap<string, integer> crunchifyconcurrenthashmapobject =NULL; Public Static voidMain (string[] args) throws Interruptedexception {//Test with Hashtable ObjectCrunchifyhashtableobject =NewHashtable<string, integer>(); Crunchifyperformtest (crunchifyhashtableobject);//Test with Synchronizedmap ObjectCrunchifysynchronizedmapobject = Collections.synchronizedmap (NewHashmap<string, integer>()); Crunchifyperformtest (Crunchifysynchronizedmapobject); //Test with Concurrenthashmap ObjectCrunchifyconcurrenthashmapobject =NewConcurrenthashmap<string, integer>(); Crunchifyperformtest (crunchifyconcurrenthashmapobject);} Public Static voidCrunchifyperformtest (Final map<string, integer>crunchifythreads) throws Interruptedexception {System. out. println ("Test started for:"+Crunchifythreads.getclass ());LongAveragetime =0; for(inti =0; I <5; i++) { LongStartTime =System.nanotime (); Executorservice Crunchifyexserver=Executors.newfixedthreadpool (thread_pool_size); for(intj =0; J < Thread_pool_size; J + +) {Crunchifyexserver.execute (NewRunnable () {@SuppressWarnings ("Unused") @Override Public voidrun () { for(inti =0; I <500000; i++) {Integer Crunchifyrandomnumber= (int) Math.ceil (Math.random () *550000); //Retrieve value. We is not using it anywhereInteger Crunchifyvalue = crunchifythreads.Get(string.valueof (Crunchifyrandomnumber));//Put ValueCrunchifythreads.put (string.valueof (Crunchifyrandomnumber), crunchifyrandomnumber);}});} //Make sure executor stopsCrunchifyexserver.shutdown ();//Blocks until all tasks has completed execution after a shutdown requestcrunchifyexserver.awaittermination (Long.max_value, timeunit.days);LongEnttime =system.nanotime ();LongTotalTime = (enttime-starttime)/1000000L; Averagetime+=TotalTime; System. out. println ("2500K entried added/retrieved in"+ TotalTime +"Ms");} System. out. println (" for"+ crunchifythreads.getclass () +"The average time is"+ Averagetime/5+"ms\n");}}
Result
Test started for:classJava.util.Hashtable500K Entried added/retrievedinch 1432ms500k Entried added/retrievedinch 1425ms500k Entried added/retrievedinch 1373ms500k Entried added/retrievedinch 1369ms500k Entried added/retrievedinch 1438msforclassJava.util.Hashtable the average time1407Ms Test started for:classjava.util.collections$synchronizedmap500k Entried added/retrievedinch 1431ms500k Entried added/retrievedinch 1460ms500k Entried added/retrievedinch 1387ms500k Entried added/retrievedinch 1456ms500k Entried added/retrievedinch 1406msforclassJava.util.collections$synchronizedmap the average time1428Ms Test started for:classJava.util.concurrent.ConcurrentHashMap500K Entried added/retrievedinch 413ms500k Entried added/retrievedinch 351ms500k Entried added/retrievedinch 427ms500k Entried added/retrievedinch 337ms500k Entried added/retrievedinch 339msforclassJava.util.concurrent.ConcurrentHashMap the average time373Ms <== Much Faster
Java Concurrenthashmap Learning--hashmap vs. Concurrenthashmap vs. Synchronizedmap–how A HashMap can be Synchronized in Java