Java Segmented Lock β
π§© 1. Problem Background: Why Do We Need a βSegmented Lockβ? β
In a multithreaded environment, if you want multiple threads to safely access a shared Map
(e.g., HashMap
), the simplest approach is:
Map<K, V> map = Collections.synchronizedMap(new HashMap<>());
This locks the entire Map. β Result: any thread accessing the Map must wait for the lock, even if they operate on different keys.
Performance issue example:
- Thread A executes
put(key1, value1)
- Thread B executes
get(key2)
Even though they access different keys, they block each other. π©
The solution: segmented lock.
βοΈ 2. Core Idea of Segmented Lock β
In one sentence:
Split a big lock into multiple smaller locks, each segment managing a portion of the data.
Visualization:
ConcurrentHashMap
βββ Segment[0] β manages a portion of buckets
βββ Segment[1] β manages a portion of buckets
βββ Segment[2] β manages a portion of buckets
βββ ...
Each Segment
has its own lock. When accessing a key:
- Hash the key to determine its segment
- Lock only that segment
- Other segments remain accessible
π Concurrency increases significantly.
π§ 3. Java Implementation (JDK 1.7 Example) β
In JDK 1.7 ConcurrentHashMap
:
- Internally:
Segment<K,V>[] segments
- Each
Segment
extendsReentrantLock
- Each
Segment
maintains its own smallHashEntry[]
Diagram:
ConcurrentHashMap
βββ Segment[0] β Lock A β HashEntry[] A
βββ Segment[1] β Lock B β HashEntry[] B
βββ Segment[2] β Lock C β HashEntry[] C
βββ ...
When executing:
map.put("key", value);
Flow roughly:
- Compute the keyβs hash
- Locate the corresponding Segment
- Acquire the segmentβs lock
- Modify the internal bucket/chain
- Release the lock
β‘ Threads operating on different segments can run in parallel.
π 4. Changes in JDK 1.8+ β
In JDK 1.8+, ConcurrentHashMap
removed the explicit Segment structure, adopting finer-grained Node + CAS + synchronized:
- No explicit segments
- Use
synchronized
on individual buckets or tree nodes - CAS reduces lock contention
Conceptually, itβs still the segmented lock idea:
Lock only the necessary portion, reducing contention.
π 5. Comparison Table β
Approach | Lock Granularity | Feature | Analogy |
---|---|---|---|
HashMap + synchronized | Whole Map | Simple but slow | Only one person at a time |
ConcurrentHashMap (JDK 1.7) | Segment-level | Parallel per segment | Multiple supermarket checkout counters |
ConcurrentHashMap (JDK 1.8+) | Node-level + CAS | Finer granularity | Lock each shelf individually |
π§© 6. Example Code (Conceptual) β
public class SegmentLockDemo {
private final int segmentCount = 16;
private final Object[] locks = new Object[segmentCount];
private final Map<Integer, String>[] maps = new Map[segmentCount];
public SegmentLockDemo() {
for (int i = 0; i < segmentCount; i++) {
locks[i] = new Object();
maps[i] = new HashMap<>();
}
}
private int getSegmentIndex(Object key) {
return key.hashCode() & (segmentCount - 1);
}
public void put(Integer key, String value) {
int index = getSegmentIndex(key);
synchronized (locks[index]) {
maps[index].put(key, value);
}
}
public String get(Integer key) {
int index = getSegmentIndex(key);
synchronized (locks[index]) {
return maps[index].get(key);
}
}
}
Each key maps to a specific lock/segment, enabling concurrent access for different keys.
β 7. Key Takeaway β
Segmented lock is a concurrency strategy that trades space for time. By splitting a single global lock into multiple independent locks, it significantly improves concurrent performance.
- JDK 1.7: explicit
Segment
implementation- JDK 1.8+: evolved into finer-grained Node-level locks + CAS.