Course contents

Hashtable, synchronizedMap and the concurrent maps

Hashtable, synchronizedMap, ConcurrentMap, ConcurrentHashMap and ConcurrentSkipListMap: locking models, atomic updates, iterators and sorted concurrent maps.

PremiumMust know for interviewsLesson14 min readCoreReviewed Oct 2026 · Java 21
On this page
  1. Picture it first: one turnstile or many lanes
  2. Hashtable and synchronizedMap under the hood
  3. ConcurrentMap: make the whole operation atomic
  4. ConcurrentHashMap at a high level
  5. ConcurrentSkipListMap: sorted and concurrent
  6. Comparison table: the thread-safe map choices
  7. How to say it in the interview

🧵 What are Hashtable, synchronizedMap and the concurrent maps?

These are Java's main answers to the question "can multiple threads share this map?" Hashtable synchronizes every method because it comes from Java 1.0, Collections.synchronizedMap wraps a normal map with one mutex, and ConcurrentMap implementations are designed so common updates do not put the whole map behind one lock. In an interview, the difference between them is the difference between "thread-safe call" and "thread-safe operation".

For this lesson, we'll focus on Hashtable, Collections.synchronizedMap, the ConcurrentMap atomic methods, a high-level view of ConcurrentHashMap, and ConcurrentSkipListMap for sorted concurrent keys. We'll keep the deep internals of ConcurrentHashMap for the Concurrency module. Here, the goal is to choose the right map and avoid the classic race: map.put(k, map.get(k) + 1).

Below the line (out of scope)

The 30-second answer

Hashtable is legacy: every public method is synchronized, it allows no null keys or values, and it still exposes Enumeration. Collections.synchronizedMap(map) is a wrapper with one mutex; each call is protected, but compound actions and iteration still need your own synchronized (map) { ... } block. ConcurrentMap adds atomic methods such as putIfAbsent, replace(k, old, new), compute and merge, which are the methods you use instead of check-then-act code. ConcurrentHashMap in Java 8+ no longer uses segment locks: it CASes into empty bins and synchronizes on the first node of a non-empty bin for updates, has weakly consistent iterators, rejects null, and treats size() as an estimate under concurrent updates, with mappingCount() for a long count. ConcurrentSkipListMap is a concurrent sorted NavigableMap backed by a skip list, with expected O(log n) operations.

What you’ll learn

  • Explain why Hashtable is legacy: synchronized methods, no nulls, and old Enumeration APIs
  • Use Collections.synchronizedMap safely, including manual synchronization while iterating
  • Avoid check-then-act races by using ConcurrentMap atomic methods like putIfAbsent, compute, merge and replace
  • Describe ConcurrentHashMap at a high level in Java 8+: CAS into empty bins and synchronized blocks on bin heads
  • Explain weakly consistent iterators, no-null rules, and why mappingCount() is preferred for large concurrent maps
  • Choose ConcurrentSkipListMap when you need a sorted concurrent NavigableMap with O(log n) operations

Interview radar

Asked very often: HashMap vs Hashtable vs ConcurrentHashMap, and Collections.synchronizedMap vs ConcurrentHashMap. Senior rounds probe: Why ConcurrentHashMap rejects null, why get returning null is ambiguous under concurrency, and why atomic methods matter more than synchronized individual calls. Production angle: A shared counter map that loses increments under load because each individual map call is safe, but the read-modify-write sequence is not.

01Picture it first: one turnstile or many lanes

A synchronized wrapper is like putting one turnstile in front of the whole building. It is easy to reason about, and only one person enters at a time. ConcurrentHashMap is closer to a supermarket with many checkout lanes: different bins can often be updated independently, while a busy bin still has a local queue.

The diagram below is the one I draw when someone says "but synchronizedMap is thread-safe too". Both protect structure; they do not scale the same way.

Fig. 1

A synchronizedMap wraps the whole map behind one mutex, while ConcurrentHashMap lets different bins proceed independently and only synchronizes on a bin head when that bin needs an update

A synchronizedMap wraps the whole map behind one mutex, while ConcurrentHashMap lets different bins proceed independently and only synchronizes on a bin head when that bin needs an update

Notice that this is a locking model, not a magic promise that every business operation is atomic. If your operation is "read, calculate, write", it must be one map method such as merge or compute, or one external synchronized block.

02Hashtable and synchronizedMap under the hood

Hashtable is the old built-in synchronized map. Each public method, including get, put, remove, containsKey and size, synchronizes on the Hashtable object. That means a read blocks a write and a write blocks a read, even when the keys live in different buckets.

It also has old API baggage. It rejects null keys and null values, it has keys() and elements() methods that return Enumeration, and it predates the Collections Framework interfaces that arrived in Java 1.2. You will mostly see it in older code, framework defaults and interview comparisons.

Collections.synchronizedMap is more useful to know because it wraps any Map you choose:

Map<String, Integer> counts = Collections.synchronizedMap(new HashMap<>());
counts.put("paid", 1);      // synchronized through the wrapper
Integer paid = counts.get("paid");

Each wrapper method synchronizes on one mutex. By default that mutex is the wrapper object itself. The important rule is in the Javadoc: when iterating over a view, you must synchronize manually on the wrapper map.

Try it yourself first

This map is synchronized. Why can the loop still fail or see inconsistent behaviour?

Map<String, Integer> counts = Collections.synchronizedMap(new HashMap<>());
counts.put("NEW", 2);
counts.put("PAID", 5);

for (String status : counts.keySet()) {        // wrong: no external lock
    System.out.println(status + "=" + counts.get(status));
}

The keySet() call is synchronized, but it returns a view. The iterator then runs through several calls, and those calls are not automatically wrapped in one long critical section. Another thread can modify the map between iterator steps.

Here is the version you should write if you choose a synchronized wrapper:

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

synchronized (counts) {
    for (Map.Entry<String, Integer> entry : counts.entrySet()) {
        System.out.println(entry.getKey() + "=" + entry.getValue());
    }
}
Where candidates slip

Many candidates say "synchronizedMap fixes thread safety" and stop there. It fixes individual map method calls. It does not make a sequence of calls atomic, and it does not automatically lock a full iteration. If you need to compose operations, either hold the same lock yourself or use a concurrent map method that composes the operation for you.

03ConcurrentMap: make the whole operation atomic

The ConcurrentMap interface exists because a single safe get and a single safe put are not enough. The race happens in the gap between them. Two threads can read the same old value, both compute the same new value, and one update overwrites the other.

This is the scenario question in real form: multiple threads need to access and update a shared collection without data inconsistency. For a shared key-value structure, the default answer is ConcurrentHashMap, through the ConcurrentMap API.

Try it yourself first

Four threads each increment paid 100,000 times. What should the final value be, and why might the first version print less?

Premium lesson

Keep reading with the Java Pass

The rest of this lesson is part of Java One-Stop Interview Prep: in-depth explanations, diagrams, model answers and how to say them in the interview.

  • ConcurrentHashMap at a high level
  • ConcurrentSkipListMap: sorted and concurrent
  • Comparison table: the thread-safe map choices
  • How to say it in the interview

From ₹199 · one-time payment · No auto-renewal

Practise this topicMaps: interview questions & scenarios
Further reading (7)