Why HashMap Can Deadlock and Crash Your JVM – Hidden Risks of Concurrent Access
This article explains how using a non‑thread‑safe HashMap in a multithreaded Java program can cause deadlocks, CPU spikes, and memory leaks, analyzes the underlying cause in the put method, and presents safer alternatives such as Collections.synchronizedMap and ConcurrentHashMap.
Introduction
Most Java developers know that HashMap is not thread‑safe, but its concurrency problems go beyond simple data corruption. Under multithreaded access it can cause deadlocks that lead to 100% CPU usage and memory exhaustion.
1. Sample Program
The following program launches 100 threads, each inserting 50,000 entries into a shared HashMap. The expectation is a final size of 5,000, but the program often hangs, spikes CPU to 100%, and consumes excessive memory.
import java.util.HashMap;
import java.util.Map;
public class HashMapManyThread {
static Map<String, String> map = new HashMap<String, String>(16);
public static class TestHashMapThread implements Runnable {
int start = 0;
public TestHashMapThread(int start) { this.start = start; }
@Override
public void run() {
for (int i = 0; i < 100000; i += 2) {
System.out.println("--puting----");
map.put(Integer.toString(i), String.valueOf(Math.random() * 100));
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread[] threads = new Thread[100];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new TestHashMapThread(i));
}
for (int i = 0; i < 100; i++) {
threads[i].start();
}
System.out.println(map.size());
}
}2. Cause Analysis
Running the program shows all threads stuck in an infinite loop inside HashMap.put. The relevant source of HashMap.put (line 374) iterates over a bucket’s linked list:
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) { // line 374
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}During concurrent traversal, two threads can corrupt the linked‑list pointers, creating a cycle (e.g., e1.next points to e2 while e2.next points back to e1). This satisfies the four classic deadlock conditions:
Mutual exclusion – both threads hold exclusive access to nodes.
Hold and wait – each thread holds one node while requesting the other.
No preemption – nodes are released only when the thread finishes.
Circular wait – the two nodes form a circular chain.
3. Deadlock Conditions
The article reviews the four necessary conditions for deadlock and shows how the corrupted linked list in HashMap meets each one.
4. Solutions
4.1 Use Collections.synchronizedMap
Wrap the map with Collections.synchronizedMap to serialize all accesses.
static Map<String, String> map = Collections.synchronizedMap(new HashMap<String, String>());The wrapper synchronizes on an internal mutex, ensuring only one thread executes put at a time. This is simple but can degrade performance due to blocking.
4.2 Use ConcurrentHashMap
Replace HashMap with ConcurrentHashMap, which employs fine‑grained locking (via ReentrantLock) to achieve thread safety without the severe contention of a fully synchronized map.
static Map<String, String> map = new ConcurrentHashMap<String, String>();
public V put(K key, V value) {
if (value == null) throw new NullPointerException();
int hash = hash(key.hashCode());
return segmentFor(hash).put(key, hash, value, false);
}
V put(K key, int hash, V value, boolean onlyIfAbsent) {
lock(); // acquire segment lock
try {
// ... standard insertion logic with rehashing ...
} finally {
unlock();
}
}Because each segment locks independently, concurrency is much higher while still preventing the deadlock scenario.
5. Conclusion
Using a plain HashMap in a multithreaded environment can cause deadlocks, CPU spikes, and memory leaks. Developers should avoid it for concurrent use and prefer ConcurrentHashMap or a synchronized wrapper, understanding the trade‑offs between simplicity and performance.
Source: https://www.cnblogs.com/wyq178/archive/2004/01/13/8676655.html
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ITFLY8 Architecture Home
ITFLY8 Architecture Home - focused on architecture knowledge sharing and exchange, covering project management and product design. Includes large-scale distributed website architecture (high performance, high availability, caching, message queues...), design patterns, architecture patterns, big data, project management (SCRUM, PMP, Prince2), product design, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
