In this post, we will learn the difference between HashMap and ConcurrentHashMap in Java. This is a frequently asked question in Java interviews for beginners. Let's dive into it.
Difference between HashMap and ConcurrentHashMap in Java
Features | HashMap | ConcurrentHashMap |
---|---|---|
Thread Safety | HashMap is not internally synchronized and hence it is not thread-safe. | ConcurrentHashMap is internally synchronized and hence it is thread-safe. |
Introduction | HashMap is part of the Java collection framework since JDK 1.2. | ConcurrentHashMap was introduced in JDK 1.5 as an alternative to Hashtable. |
Null Keys and Values | HashMap allows a maximum of one null key and any number of null values. | ConcurrentHashMap doesn’t allow even a single null key and null value. |
Iterator's Nature | Iterators returned by HashMap are fail-fast in nature. | Iterators returned by ConcurrentHashMap are fail-safe in nature. |
Performance | HashMap is faster (because it is not internally synchronized) | ConcurrentHashMap is slower (because it is internally synchronized) |
Suitability | Most suitable for single-threaded applications. | Most suitable for multi-threaded applications. |
Example
Let's create an example to illustrate the difference between HashMap and ConcurrentHashMap in Java.
HashMap is a non-thread-safe implementation of a map, where elements can be added, updated, and removed. However, it is not suitable for concurrent access from multiple threads without proper synchronization, as it may lead to unexpected behavior or even data corruption.
ConcurrentHashMap, on the other hand, is a thread-safe implementation of a map, designed to support high concurrency. It allows multiple threads to read and write concurrently without external synchronization. It achieves this by dividing the map into segments and applying separate locks to each segment.
Let's see an example:
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
public class HashMapVsConcurrentHashMapExample {
public static void main(String[] args) {
// HashMap example (non-thread-safe)
HashMap<Integer, String> hashMap = new HashMap<>();
Runnable hashMapRunnable = () -> {
for (int i = 0; i < 5; i++) {
hashMap.put(i, "Value " + i);
String value = hashMap.get(i);
System.out.println("HashMap - Key: " + i + ", Value: " + value);
}
};
// Create multiple threads using the same Runnable (not thread-safe)
Thread hashMapThread1 = new Thread(hashMapRunnable);
Thread hashMapThread2 = new Thread(hashMapRunnable);
// Start the threads
hashMapThread1.start();
hashMapThread2.start();
// ConcurrentHashMap example (thread-safe)
ConcurrentHashMap<Integer, String> concurrentHashMap = new ConcurrentHashMap<>();
Runnable concurrentHashMapRunnable = () -> {
for (int i = 0; i < 5; i++) {
concurrentHashMap.put(i, "Value " + i);
String value = concurrentHashMap.get(i);
System.out.println("ConcurrentHashMap - Key: " + i + ", Value: " + value);
}
};
// Create multiple threads using the same Runnable (thread-safe)
Thread concurrentHashMapThread1 = new Thread(concurrentHashMapRunnable);
Thread concurrentHashMapThread2 = new Thread(concurrentHashMapRunnable);
// Start the threads
concurrentHashMapThread1.start();
concurrentHashMapThread2.start();
}
}
Output:
HashMap - Key: 0, Value: Value 0
HashMap - Key: 0, Value: Value 0
HashMap - Key: 1, Value: Value 1
HashMap - Key: 1, Value: Value 1
HashMap - Key: 2, Value: Value 2
HashMap - Key: 2, Value: Value 2
HashMap - Key: 3, Value: Value 3
HashMap - Key: 3, Value: Value 3
HashMap - Key: 4, Value: Value 4
HashMap - Key: 4, Value: Value 4
ConcurrentHashMap - Key: 0, Value: Value 0
ConcurrentHashMap - Key: 0, Value: Value 0
ConcurrentHashMap - Key: 1, Value: Value 1
ConcurrentHashMap - Key: 1, Value: Value 1
ConcurrentHashMap - Key: 2, Value: Value 2
ConcurrentHashMap - Key: 2, Value: Value 2
ConcurrentHashMap - Key: 3, Value: Value 3
ConcurrentHashMap - Key: 3, Value: Value 3
ConcurrentHashMap - Key: 4, Value: Value 4
ConcurrentHashMap - Key: 4, Value: Value 4
Explanation:
In the example, we first demonstrate the behavior of HashMap, which is not thread-safe. We create two threads that execute the same hashMapRunnable, which adds elements to the HashMap. The threads may interfere with each other and cause unexpected behavior, leading to incorrect or missing output. This demonstrates that HashMap is not suitable for concurrent access from multiple threads without proper synchronization.
Next, we demonstrate the behavior of ConcurrentHashMap, which is thread-safe. We create two threads that execute the same concurrentHashMapRunnable, which adds elements to the ConcurrentHashMap.
Since ConcurrentHashMap is designed for concurrent access, it properly handles multiple threads accessing it simultaneously, and we get consistent and correct output.
Note: The actual output may vary in different runs due to the concurrent nature of the threads. The key takeaway is that ConcurrentHashMap is suitable for concurrent access, while HashMap is not.
References
Related Collections Interview QA
- map() vs flatMap() in Java
- Collections vs Streams
- ArrayList vs Vector
- Iterator vs ListIterator
- HashMap vs HashTable
- HashSet vs HashMap
- Array vs ArrayList
- Fail-Fast Iterators vs Fail-Safe Iterators
- HashMap vs ConcurrentHashMap
- LinkedList vs ArrayDeque
- LinkedList vs Array
- LinkedList vs Doubly LinkedList
- Enum vs EnumSet in Java
- HashMap vs. TreeMap in Java
- Synchronized Collections vs. Concurrent Collections