Using HashMap in multi-threaded application can cause issues when multiple threads try to perform some modification operations on the same HashMap instance.

Synchronization of HashMap
Hashtable or Collections.synchronizedMap
ConcurrentHashMap

There are multiple ways by which a HashMap instance can be made synchronized and thread safe. The exact solution to this depends upon the actual requirement. However one can make HashMap thread safe by using the following guidelines:

  • Synchronization of HashMap

    If you want to stick to HashMap only due to JDK limitations then you need to ensure that any modification to the HashMap is made only from a synchronized context.

    You need to ensure that proper locking mechanism is in place when trying to add or remove elements from the same HashMap instance using multiple threads.

  • Hashtable or Collections.synchronizedMap

    Collections.synchronizedMap(new HashMap()); is used to get a synchronized map wrapper around an earlier created HashMap. The Collections class is a helper class which provides a number of methods related to sorting and synchronization of underlying collection classes.

    When we use synchronizedMap from Collections class, the operations on the returned wrapper get synchronized. The total effect is as if the methods of the underlying map have been marked as synchronized. The code for this method looks like:

    private final Map<K,V> m;     // Backing Map
    final Object      mutex;        // Object on which to synchronize
    
            SynchronizedMap(Map<K,V> m) {
                if (m==null)
                    throw new NullPointerException();
                this.m = m;
                mutex = this;
            }
    
            SynchronizedMap(Map<K,V> m, Object mutex) {
                this.m = m;
                this.mutex = mutex;
            }
    
            public int size() {
                synchronized (mutex) {return m.size();}
            }
            public boolean isEmpty() {
                synchronized (mutex) {return m.isEmpty();}
            }
            public boolean containsKey(Object key) {
                synchronized (mutex) {return m.containsKey(key);}
            }
    ................
    ................
    

    Thus an object named as mutex is used as lock and any methods on the wrapper collection are in effect translated to calls on underlying map with additional synchronization using the mutex (which is a member reference variable)

    While using the wrapper map returned by Collections.synchronizedMap method, make sure to synchronize multiple operations so that they become atomic operations.

    For example:
    If one thread is trying to add two key/value pair to synchronized map followed by a remove operation. Another thread is trying to remove two key/value pair followed by one add operation. Each add and remove operation is getting synchronized due the code inside the wrapper created by Collections class. But the three operations performed by first thread may get interleaved by the three operations from the second thread. This will result in unexpected results and can only be avoided by adding synchronization so that three operations in any of the thread become single operation.

    Moreover, it is advised by JDK to perform manual synchronization when accessing the elements of wrapper, for example the keyset for the wrapper map object. The synchronization level provided by synchronizedMap wrapper is same as that provided by Hashtable class.

    Due to the involvement of additional synchronization, there is performance degradation seen when using the wrapper map in multi-threaded applications. Apart from synchronized map wrapper implementation, Collections class can also provide synchronized wrapper for ArrayList. So Collections class is not limited to hashcode based collections only.

  • ConcurrentHashMap

    The performance issues described in the use of Collections.synchronizedMap can be addressed by the use ConcurrentHashMap class. The ConcurrentHashMap class uses a number of locks to add synchronization to the map operations.

    Some salient features about ConcurrentHashMap which can help understand the working of ConcurrentHashMap in details are:
    a) This class doesn’t lock the read operations. Only add and remove operations are locked.
    b) The use of this class is different from Collections.synchronizedMap is that former uses multiple locks (maximum of 32) for write operations where as the latter locks the whole map. This means that 32 different threads could be modifying the same ConcurrentHashMap at a single point of time where as only one thread can modify Hashtable or Collections.synchronizedMap.

    Thus, if performance is on your mind then do use ConcurrentHashMap instead if Collections.synchronizedMap.

Related Posts

Difference between Hashtable, Collections.synchronizedMap and ConcurrentHashMap admin Core Java
Using HashMap in multi-threaded application can cause issues when multiple threads try to perform some modification operations on the same HashMap instance. Synchronization of HashMap Hashtable or Collections.synchronizedMap ConcurrentHashMap There are multiple ways by which a HashMap instance can be made synchronized and thread safe. The exact solution to this depends upon...
Using HashMap in multi-threaded application can cause issues when multiple threads try to perform some modification operations on the same HashMap instance. <a href="#hashmap">Synchronization of HashMap</a> <a href="#synchronizedmap">Hashtable or Collections.synchronizedMap</a> <a href="#concurrentmap">ConcurrentHashMap</a> There are multiple ways by which a <a href="http://www.javaexperience.com/5-ways-to-sort-hashmap-in-java-based-on-keys-or-values/" title="5 ways to sort HashMap in Java based on keys or values">HashMap instance</a> can be made synchronized and thread safe. The exact solution to this depends upon the actual requirement. However one can make HashMap thread safe by using the following guidelines: <ul> <li><h3>Synchronization of HashMap</h3> <a name="hashmap"></a> If you want to stick to HashMap only due to JDK limitations then you need to ensure that any modification to the HashMap is made only from a <strong>synchronized context</strong>. You need to ensure that proper locking mechanism is in place when trying to add or remove elements from the same HashMap instance using multiple threads. </li> <li><h3>Hashtable or Collections.synchronizedMap</h3> <a name="synchronizedmap"></a> Collections.synchronizedMap(new HashMap()); is used to get a synchronized map wrapper around an earlier created HashMap. The Collections class is a helper class which provides a number of methods related to <a href="http://www.javaexperience.com/5-ways-to-sort-hashmap-in-java-based-on-keys-or-values/" title="5 ways to sort HashMap in Java based on keys or values">sorting and synchronization</a> of underlying collection classes. When we use synchronizedMap from Collections class, the operations on the <strong>returned wrapper get synchronized</strong>. The total effect is as if the methods of the underlying map have been marked as synchronized. The code for this method looks like: 1 Thus an object named as mutex is used as lock and any methods on the wrapper collection are in effect translated to calls on underlying map with additional synchronization using the mutex (which is a member reference variable) While using the wrapper map returned by Collections.synchronizedMap method, make sure to synchronize multiple operations so that they become atomic operations. <strong>For example:</strong> If one thread is trying to add two key/value pair to synchronized map followed by a remove operation. Another thread is trying to remove two key/value pair followed by one add operation. Each add and remove operation is getting synchronized due the code inside the wrapper created by Collections class. But the three operations performed by first thread may get interleaved by the three operations from the second thread. This will result in unexpected results and can only be avoided by adding synchronization so that three operations in any of the thread become single operation. Moreover, it is advised by JDK to perform manual synchronization when accessing the elements of wrapper, for example the keyset for the wrapper map object. The synchronization level provided by synchronizedMap wrapper is same as that provided by <a href="http://www.javaexperience.com/differences-between-hashmap-and-hashtable-in-java/" title="Differences between HashMap and Hashtable in Java">Hashtable class</a>. Due to the involvement of additional synchronization, <strong>there is performance degradation seen when using the wrapper map</strong> in multi-threaded applications. Apart from synchronized map wrapper implementation, Collections class can also provide synchronized wrapper for ArrayList. So Collections class is not limited to <a href="http://www.javaexperience.com/java-dive-deep-into-hashcode-internals/" title="Dive deep into Hashcode Internals">hashcode based collections</a> only. </li> <li> <h3>ConcurrentHashMap</h3> <a name="concurrentmap"></a> The performance issues described in the use of Collections.synchronizedMap can be addressed by the use ConcurrentHashMap class. The ConcurrentHashMap class uses a number of locks to add synchronization to the map operations. Some salient features about ConcurrentHashMap which can help understand the working of ConcurrentHashMap in details are: a) This class doesn't lock the read operations. Only add and remove operations are locked. b) The use of this class is different from Collections.synchronizedMap is that former uses multiple locks (maximum of 32) for write operations where as the latter locks the whole map. This means that 32 different threads could be <strong>modifying the same ConcurrentHashMap at a single point</strong> of time where as only one thread can modify Hashtable or Collections.synchronizedMap. Thus, if <a href="http://www.javaexperience.com/performance-management-for-web-applications/" title="Performance Management in web applications">performance</a> is on your mind then do use ConcurrentHashMap instead if Collections.synchronizedMap. </li> </ul>
Object and Class level locks in Java
Best Practicies for adding code comments
The following two tabs change content below.
I run this blog with lots of passion. In this website, you will find tutorials on Core Java, Spring, Struts, Web Applications, Portals and Database. Please support me and the website by sharing the posts on your facebook / twitter. You can tap the share button at the top of each post. Thanks for the support.

Comments

comments