Java Collections + Concurrency

What is the difference between HashMap and ConcurrentHashMap?

HashMap is not thread-safe. ConcurrentHashMap is designed for safe concurrent reads and updates without locking the entire map.

CollectionsConcurrencySenior Java

The Short Answer

HashMap is fast and commonly used, but it is not safe when multiple threads modify it at the same time.

ConcurrentHashMap is designed for concurrent access. It lets multiple threads safely read and update the map with much better scalability than locking one entire HashMap.

The Real Problem

Imagine 100 threads updating a leaderboard, cache, request counter, or session map at the same time.

With a plain HashMap, two threads can interfere with each other. One thread may overwrite another thread's update, or one thread may observe the map while another thread is changing its internal structure.

Lost Update / Overwrite

counter = 5
Thread A reads 5
Thread B reads 5
A writes 6
B writes 6
Expected 7, actual 6

Both threads read the same old value and write back the same new value. One update disappears.

Reading During Mutation

Thread A resizing / reorganizing map
Bucket A
Bucket B
Bucket C
changes to
Bucket A
New bucket layout
Thread B reads halfway through

A map is not just key-value pairs. It has internal structure. If one thread reads while another changes that structure, the reader may observe an unsafe intermediate state.

The issue is not that HashMap is bad. The issue is that HashMap was not designed for concurrent mutation.

Why Not Just Lock the Whole HashMap?

You could do this:

java
Map<String, Integer> scores = Collections.synchronizedMap(new HashMap<>());

This can make access safer, but it usually means one major lock controls access to the map. If many threads are using the map, they wait on that same lock.

That may be correct, but it can become slow. It is like having 100 cashiers but forcing every customer to use one checkout line.

The Mental Model

Synchronized HashMap

One Big Lock

Entire Map

Many operations may compete for the same lock, even if they are touching unrelated keys.

ConcurrentHashMap

More Fine-Grained Concurrency

Bucket / Bin
Bucket / Bin
Bucket / Bin
Bucket / Bin

ConcurrentHashMap does not lock the entire map for every operation. It allows more parallelism.

Important: Thread-Safe Does Not Mean Every Pattern Is Safe

ConcurrentHashMap makes individual operations safe, but you still need to be careful with multi-step logic.

This pattern is risky:

java
if (!map.containsKey(userId)) {
    map.put(userId, new UserSession());
}

Prefer atomic methods like:

java
map.computeIfAbsent(userId, id -> new UserSession());

Simple Counter Example

java
ConcurrentHashMap<String, LongAdder> requestCounts =
    new ConcurrentHashMap<>();

public void recordRequest(String endpoint) {
    requestCounts
        .computeIfAbsent(endpoint, key -> new LongAdder())
        .increment();
}

Common Interview Follow-Ups

Does ConcurrentHashMap lock the whole map?

No. That is one of the main reasons it scales better than synchronizing an entire HashMap.

Can race conditions still happen?

Yes, if your business logic uses unsafe multi-step patterns.

Final Takeaway

HashMap is for normal single-threaded or externally controlled use. ConcurrentHashMap is for shared maps in concurrent systems where you care about both correctness and throughput.