Why ConcurrentHashMap.get() in Java 8 Is Lock‑Free
This article explains how Java 8's ConcurrentHashMap implements the get operation without acquiring locks by using volatile fields, CAS, and a simplified node structure, contrasting it with the segment‑based design of JDK 1.7 and detailing the memory‑visibility guarantees provided by volatile.
ConcurrentHashMap (Java 1.8) is a thread‑safe concurrent collection whose get operation executes without any explicit locking, raising the question of how it avoids dirty reads.
Background : In JDK 1.7 the implementation relied on Segment + HashEntry + ReentrantLock . Java 1.8 replaced the bulky Segment design with a simpler Node + CAS + synchronized approach, reducing lock granularity from segment‑level to individual hash entries.
Key differences :
Lock granularity is finer in JDK 1.8 (per hash entry rather than per segment).
The data structure is simpler, using synchronized for updates and eliminating the need for segment locks.
Long chains are replaced by red‑black trees when a bucket exceeds a threshold, improving lookup performance.
get operation source code (excerpt):
public V get(Object key) {
Node
[] tab; Node
e, p; int n, eh; K ek;
int h = spread(key.hashCode()); // compute hash
if ((tab = table) != null && (n = tab.length) > 0 &&
(e = tabAt(tab, (n - 1) & h)) != null) { // read first node
if ((eh = e.hash) == h) { // first node matches
if ((ek = e.key) == key || (ek != null && key.equals(ek)))
return e.val;
}
// handle forwarding node, tree bin, or list traversal
else if (eh < 0)
return (p = e.find(h, key)) != null ? p.val : null;
while ((e = e.next) != null) {
if (e.hash == h && ((ek = e.key) == key || (ek != null && key.equals(ek))))
return e.val;
}
}
return null;
}The method never acquires a lock; visibility and ordering are ensured by the volatile keyword.
Role of volatile : It guarantees that writes to volatile variables are immediately flushed to main memory and that subsequent reads see the latest value, preventing stale data without providing atomicity. For reference types (e.g., arrays), volatile ensures the reference itself is visible, not the contents.
In ConcurrentHashMap, the table array is declared as transient volatile Node [] table; so that during resizing the new bucket array becomes visible to other threads. The individual Node fields volatile V val and volatile Node next make updates to values and linked‑list pointers visible to concurrent readers.
Node definition (excerpt):
static class Node
implements Map.Entry
{
final int hash;
final K key;
volatile V val;
volatile Node
next;
// constructors and methods omitted for brevity
}Because val and next are volatile, a thread reading a node sees the most recent value and link, allowing the get operation to be lock‑free.
Summary :
Java 8's ConcurrentHashMap get() is lock‑free, contributing to its high performance compared to Hashtable or synchronizedMap.
The lock‑free property stems from volatile fields in Node , not from the volatile array itself.
The volatile array ensures visibility during resizing, while volatile node fields guarantee safe reads of values and links.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
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.