This post shows how to synchronize HashMap in Java and the HashMap’s thread safe alternative which can be used.
HashMap is not thread safe
If HashMap is accessed by multiple threads concurrently and at least one of the threads modifies the map structurally, you must synchronize HashMap externally. Note that structural modification is any operation that adds or deletes one or more mappings; merely changing the value associated with a key that an instance already contains is not a structural modification.
Options for thread-safe Map
If you want to synchronize HashMap in Java or looking for a thread-safe alternative of HashMap then there are following options.
- Use Collections.synchronizedMap() to synchronize Map- This method returns a synchronized (thread-safe) map backed by the specified map. In case you are synchronizing a TreeMap which is a sorted Map you can use
synchronizedSortedMap()
method - Using ConcurrentHashMap- Another option is to use ConcurrentHashMap from the
java.util.concurrent
package. All of its operations are thread-safe and it provides better concurrency. ConcurrentHashMap provides better performance by using separate locks for separate buckets rather than synchronizing the whole Map on a single lock.
Using Collections.synchronizedMap()
You can synchronize your HashMap by using Collections.synchronizedMap()
method. First we’ll see an example
what happens if HashMap is used in a multi-threaded environment without synchronizing it.
In the Java example four threads are created, each of these thread adds 5 elements to the Map. After all the threads are done Map size should be 20.
import java.util.HashMap; import java.util.Map; public class MapSynchro implements Runnable{ private Map<String, String> testMap; public MapSynchro(Map<String, String> testMap){ this.testMap = testMap; } public static void main(String[] args) { // Synchronized Map Map<String, String> testMap = new HashMap<String, String>(); /// 4 threads Thread t1 = new Thread(new MapSynchro(testMap)); Thread t2 = new Thread(new MapSynchro(testMap)); Thread t3 = new Thread(new MapSynchro(testMap)); Thread t4 = new Thread(new MapSynchro(testMap)); t1.start(); t2.start(); t3.start(); t4.start(); try { t1.join(); t2.join(); t3.join(); t4.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Size of Map is " + testMap.size()); } @Override public void run() { System.out.println("in run method" + Thread.currentThread().getName()); String str = Thread.currentThread().getName(); for(int i = 0; i < 5; i++){ // adding thread name to make element unique testMap.put(str+i, str+i); try { // delay to verify thread interference Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } }Output
in run methodThread-1 in run methodThread-0 in run methodThread-2 in run methodThread-3 Size of Map is 19
In different run I got different HashMap sizes, 17, 18, 19 and 20 because of the thread interference.
Now, if we synchronize the HashMap in the same Java example using Collections.synchronizedMap() method.
public class MapSynchro implements Runnable{ private Map<String, String> testMap; public MapSynchro(Map<String, String> testMap){ this.testMap = testMap; } public static void main(String[] args) { // Synchronized Map Map<String, String> testMap = Collections.synchronizedMap(new HashMap<String, String>()); /// 4 threads Thread t1 = new Thread(new MapSynchro(testMap)); Thread t2 = new Thread(new MapSynchro(testMap)); Thread t3 = new Thread(new MapSynchro(testMap)); Thread t4 = new Thread(new MapSynchro(testMap)); t1.start(); t2.start(); t3.start(); t4.start(); try { t1.join(); t2.join(); t3.join(); t4.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Size of Map is " + testMap.size()); } @Override public void run() { System.out.println("in run method" + Thread.currentThread().getName()); String str = Thread.currentThread().getName(); for(int i = 0; i < 5; i++){ // adding thread name to make element unique testMap.put(str+i, str+i); try { // delay to verify thread interference Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } }Output
in run methodThread-2 in run methodThread-0 in run methodThread-3 in run methodThread-1 Size of Map is 20
Now the size of Map is 20 every time.
Using ConcurrentHashMap
Other than synchronizing HashMap, another option to have a thread safe HashMap is to use ConcurrentHashMap in Java. Let’s see the same example as above using ConcurrentHashMap.
import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class MapSynchro implements Runnable{ private Map<String, String> testMap; public MapSynchro(Map<String, String> testMap){ this.testMap = testMap; } public static void main(String[] args) { // Synchronized Map Map<String, String> testMap = new ConcurrentHashMap<String, String>(); /// 4 threads Thread t1 = new Thread(new MapSynchro(testMap)); Thread t2 = new Thread(new MapSynchro(testMap)); Thread t3 = new Thread(new MapSynchro(testMap)); Thread t4 = new Thread(new MapSynchro(testMap)); t1.start(); t2.start(); t3.start(); t4.start(); try { t1.join(); t2.join(); t3.join(); t4.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Size of Map is " + testMap.size()); } @Override public void run() { System.out.println("in run method" + Thread.currentThread().getName()); String str = Thread.currentThread().getName(); for(int i = 0; i < 5; i++){ // adding thread name to make element unique testMap.put(str+i, str+i); try { // delay to verify thread interference Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } }Output
in run methodThread-2 in run methodThread-0 in run methodThread-3 in run methodThread-1 Size of Map is 20
That's all for the topic How to Synchronize Java HashMap. If something is missing or you have something to share about the topic please write a comment.
You may also like
- How to Synchronize Java ArrayList
- How to Synchronize Java HashSet
- HashMap Vs LinkedHashMap Vs TreeMap Vs HashTable in Java
- Java Volatile Keyword With Examples
- throw Vs throws in Java Exception Handling
- Display Time in 24 Hour Format in Java
- Python Program to Check File or Directory Exists
- Spring Dependency Injection With Examples
No comments:
Post a Comment