Skip to content

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:

java
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:

  1. Hash the key to determine its segment
  2. Lock only that segment
  3. 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 extends ReentrantLock
  • Each Segment maintains its own small HashEntry[]

Diagram:

ConcurrentHashMap
  β”œβ”€β”€ Segment[0] β†’ Lock A β†’ HashEntry[] A
  β”œβ”€β”€ Segment[1] β†’ Lock B β†’ HashEntry[] B
  β”œβ”€β”€ Segment[2] β†’ Lock C β†’ HashEntry[] C
  └── ...

When executing:

java
map.put("key", value);

Flow roughly:

  1. Compute the key’s hash
  2. Locate the corresponding Segment
  3. Acquire the segment’s lock
  4. Modify the internal bucket/chain
  5. 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 ​

ApproachLock GranularityFeatureAnalogy
HashMap + synchronizedWhole MapSimple but slowOnly one person at a time
ConcurrentHashMap (JDK 1.7)Segment-levelParallel per segmentMultiple supermarket checkout counters
ConcurrentHashMap (JDK 1.8+)Node-level + CASFiner granularityLock each shelf individually

🧩 6. Example Code (Conceptual) ​

java
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.

Just something casual. Hope you like it. Built with VitePress