Fundamentals 7 min read

Why HashMap Is Not Thread‑Safe: A Deep Dive into the Source Code

The article explains how HashMap can enter an infinite loop, lose data, or corrupt entries when accessed concurrently, illustrates the root causes with JDK 1.7 and 1.8 source code, compares alternative thread‑safe maps, and shows how to answer this classic interview question.

Coder Life Journal
Coder Life Journal
Coder Life Journal
Why HashMap Is Not Thread‑Safe: A Deep Dive into the Source Code

What Triggers the Crash?

During a production incident the CPU spikes to 100% and the system hangs because a HashMap has turned into a circular linked list, causing an endless traversal.

Living Analogy

Imagine a community parcel locker. Normally you place a package in an empty slot, chain conflicting packages together, and expand the locker when it’s full.

Put a parcel: find an empty slot.

Two conflicting parcels: link them with a chain.

Too many parcels: enlarge the locker.

When two people try to place parcels simultaneously, the locker collapses – this is the essence of HashMap’s thread‑unsafe behavior.

Source Code Broken Down

1. Infinite Loop – Head‑Insertion During Resize (JDK 1.7)

JDK 1.7 uses head‑insertion when moving entries to a new bucket during resize:

void transfer(Entry[] newTable, boolean rehash) {
    int newCapacity = newTable.length;
    for (Entry<K,V> e : table) {
        while (null != e) {
            Entry<K,V> next = e.next; // record next node
            int i = indexFor(e.hash, newCapacity); // compute new index
            e.next = newTable[i]; // point to new bucket head
            newTable[i] = e; // insert at head
            e = next; // move to next
        }
    }
}

If two threads resize concurrently, thread A may finish e.next = newTable[i] and be pre‑empted. Thread B then runs, reversing the chain order. When thread A resumes, it continues with the stale reference, creating a circular list. Subsequent get(key) calls loop forever, maxing out the CPU.

2. Data Loss – Overwrite on put (JDK 1.8)

JDK 1.8 switches to tail‑insertion, eliminating the loop, but the put operation remains unsafe:

final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
    Node<K,V>[] tab = (Node<K,V>[])table;
    int n = (tab = resize()).length; // may trigger resize
    int i = (n - 1) & hash; // bucket index
    if ((p = tab[i]) == null) {
        tab[i] = newNode(hash, key, value, null); // directly insert
    }
    // ... other branches omitted
}

When two threads evaluate tab[i] == null simultaneously, both think the bucket is empty and each creates a new node. The later write overwrites the earlier one, so the first entry is lost.

3. Corrupted Data During Resize

If multiple threads invoke resize() at the same time, they each allocate a new array newTable and copy entries. Their operations overwrite each other’s newTable, resulting in missing or misplaced entries in the final map.

Solution Comparison

ConcurrentHashMap : Uses segment locks and red‑black trees; high performance; requires familiarity with its API. ★★★★★

Collections.synchronizedMap : Simple wrapper around HashMap; suffers from a global lock and poor performance. ⭐⭐

Hashtable : Legacy synchronized map; stable but locks the entire table and disallows null keys. ⭐

Interview Answer

The three thread‑safety issues are: Infinite loop – caused by head‑insertion during resize in JDK 1.7 (fixed in JDK 1.8). Data overwrite – two threads simultaneously see an empty bucket and the later write overwrites the earlier one. Resize corruption – concurrent calls to resize() overwrite each other’s new array. In practice, use HashMap only in single‑threaded contexts and switch to ConcurrentHashMap for concurrent access.

One‑Line Summary

HashMap behaves like a shared parcel locker: one user is fine, but multiple users cause lost parcels and a collapsed rack.
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaJDKThread SafetyHashMapConcurrentHashMapData Race
Coder Life Journal
Written by

Coder Life Journal

An ordinary programmer sharing tech and life.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.