HashMap vs ConcurrentHashMap in Java
When working with collections in Java, HashMap and ConcurrentHashMap are both commonly used to store key-value pairs.
But they are designed for different situations, especially when multiple threads are involved.
1. HashMap
HashMap stores data in the form of key-value pairs.
Map<String, Integer> map = new HashMap<>();
map.put("Java", 10);
map.put("Spring", 20);
map.put("Kafka", 30);The important point is:
HashMap is not thread-safe.
If multiple threads modify a HashMap at the same time, it can lead to inconsistent or unexpected results.
So, HashMap is generally suitable when:
- The map is accessed by a single thread
- External synchronization is already provided
- High concurrent access is not required
2. ConcurrentHashMap
ConcurrentHashMap is a thread-safe implementation of Map designed for concurrent applications.
Map<String, Integer> map = new ConcurrentHashMap<>();
map.put("Java", 10);
map.put("Spring", 20);
map.put("Kafka", 30);Multiple threads can safely read and update the map concurrently.
Thread 1 ──┐
Thread 2 ──┼──> ConcurrentHashMap
Thread 3 ──┘
↓
Thread-safe accessIt achieves concurrency without simply locking the entire map for every operation.
3. Why not just synchronize HashMap?
You can make a HashMap thread-safe using synchronization:
Map<String, Integer> map =
Collections.synchronizedMap(new HashMap<>());But this approach synchronizes access through a common lock.
With ConcurrentHashMap, concurrent operations are designed to allow better parallelism.
The idea is:
HashMap
↓
Not thread-safe
↓
Need external synchronization
ConcurrentHashMap
↓
Thread-safe
↓
Designed for concurrent access4. Important ConcurrentHashMap Features
ConcurrentHashMap provides useful atomic operations such as:
map.putIfAbsent("Java", 10);map.computeIfAbsent("Spring", key -> 20);map.compute("Java", (key, value) -> value + 1);
These operations are particularly useful when multiple threads are updating shared data.
Get Govinda Ekabote’s stories in your inbox
Join Medium for free to get updates from this writer.
For example:
ConcurrentHashMap<String, Integer> counter =
new ConcurrentHashMap<>();counter.merge("Java", 1, Integer::sum);This is safer for concurrent counting than manually doing:
counter.put("Java", counter.get("Java") + 1);because the second approach contains a read → modify → write sequence that is not atomic.
5. Real-World Example
Imagine a backend application tracking the number of requests for each API:
/api/users → 150
/api/products → 230
/api/orders → 180Many requests can arrive at the same time.
Using a normal HashMap for shared counters can create concurrency problems.
A ConcurrentHashMap is a better choice:
ConcurrentHashMap<String, Integer> requestCount =
new ConcurrentHashMap<>();requestCount.merge("/api/users", 1, Integer::sum);Multiple request-handling threads can safely update the map.
6. Which One Should You Use?
Use HashMap when:
- Your code is single-threaded
- The map is not shared between concurrent threads
- You don’t need concurrent modifications
Use ConcurrentHashMap when:
- Multiple threads access the same map
- Multiple threads can update the map
- You need thread-safe operations
- You are building concurrent or multithreaded applications
Simple rule
Single-threaded
↓
HashMap
---------------------------------------
Multi-threaded + shared map
↓
ConcurrentHashMap
The important lesson is:
Don’t choose ConcurrentHashMap simply because it is "safer." Choose it when the map is actually shared across concurrent threads.
For single-threaded code, HashMap is usually the simpler choice.









