Definition
- Striped locking – an array of N ReentrantLock instances. For any key, compute
spread(hash) & (N-1)to select which lock to acquire. N is a power of 2 for fast bitwise modulo. - Parallel access – operations on different stripes run in parallel. If key-A hashes to stripe-3 and key-B hashes to stripe-7, they use different locks and proceed concurrently.
- Unfair locks – the default ReentrantLock is unfair, allowing barging (a thread may acquire the lock without queuing). Unfair is 10-30% faster than fair because it avoids FIFO queuing and context-switch overhead.
- Use over ConcurrentHashMap – when you need atomic operations spanning multiple data structures (debit account map AND write audit log), or when you need cache stampede deduplication (100 threads miss the same key, only one loads from DB).
- Hash spreading –
spread(h) = h ^ (h >>> 16)mixes high bits into low bits for better distribution, copied from ConcurrentHashMap's design.
One vault key for all drawers at National Bank of India means 200 tellers queue for one key. Striped locking is like 16 different keys, each opening a group of drawers. Rajesh uses key-3 (drawers 30-39), Priya uses key-7 (drawers 70-79). They access drawers in parallel. Unfair keys: whoever grabs the key fastest goes first. Why striping over ConcurrentHashMap? When you need to lock drawers from two different cabinets atomically.
Understanding the Concepts
What is striped lock partitioning?
Striped locking divides a single global lock into N independent locks. Each key maps to a stripe by hashing, and only operations on the same stripe contend with each other.
package com.bank.concurrency;
import java.util.concurrent.locks.ReentrantLock;
public class StripedLock {
private final ReentrantLock[] locks;
private final int mask;
public StripedLock(int stripes) {
stripes = Integer.highestOneBit(stripes - 1) << 1; // round to power of 2
locks = new ReentrantLock[stripes];
for (int i = 0; i < stripes; i++) {
locks[i] = new ReentrantLock(); // unfair (default, faster)
}
mask = stripes - 1;
}
public ReentrantLock getLock(Object key) {
return locks[spread(key.hashCode()) & mask];
}
private static int spread(int h) {
return h ^ (h >>> 16); // mix high bits into low bits
}
}
How do you use it for per-account operations?
package com.bank.concurrency;
import java.math.BigDecimal;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
public class StripedAccountService {
private final StripedLock stripedLock = new StripedLock(16);
private final ConcurrentHashMap<String, BigDecimal> accounts = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, String> auditLog = new ConcurrentHashMap<>();
public void debit(String accountId, BigDecimal amount) {
ReentrantLock lock = stripedLock.getLock(accountId);
lock.lock();
try {
BigDecimal balance = accounts.getOrDefault(accountId, BigDecimal.ZERO);
accounts.put(accountId, balance.subtract(amount));
auditLog.put(accountId, "Debited " + amount); // multi-structure atomic!
} finally {
lock.unlock();
}
}
}
How does striped locking prevent cache stampede?
package com.bank.concurrency;
import java.math.BigDecimal;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
public class CacheStampedeProtection {
private final StripedLock cacheLock = new StripedLock(64);
private final ConcurrentHashMap<String, BigDecimal> cache = new ConcurrentHashMap<>();
public BigDecimal getBalance(String accountId) {
BigDecimal cached = cache.get(accountId);
if (cached != null) return cached;
ReentrantLock lock = cacheLock.getLock(accountId);
lock.lock(); // all threads for SAME key → same stripe → only 1 enters
try {
cached = cache.get(accountId); // double-check after lock
if (cached != null) return cached;
BigDecimal loaded = loadFromDB(accountId); // only ONE thread loads
cache.put(accountId, loaded);
return loaded;
} finally {
lock.unlock();
}
}
private BigDecimal loadFromDB(String accountId) {
return new BigDecimal("75000.00");
}
}
When should you use striped locks vs ConcurrentHashMap?
Use ConcurrentHashMap when operations are within a single map and atomicity is per-key (computeIfAbsent, merge). Use striped locks when you need atomicity across multiple data structures or when you need to prevent cache stampede for expensive loads.
What are common interview follow-up questions?
- How many stripes should you use? 16-64 is typical. More stripes reduce contention but increase memory. Profile under realistic load to find the right balance.
- Can two different keys hash to the same stripe? Yes. This is similar to hash collisions. They will contend for the same lock. With enough stripes, collisions are rare.
Visual Overview
Striped Lock: N Locks for Parallel Access ═════════════════════════════════════════ Global lock (1 lock): Striped lock (16 locks): T1 → lock → wait T1 → stripe[3] → proceed T2 → lock → wait T2 → stripe[7] → proceed (parallel!) T3 → lock → wait T3 → stripe[3] → wait (same stripe as T1) Sequential! Parallel for different stripes! Hash to stripe: accountId.hashCode() → spread() → & mask → stripe index "SAV2001" → hash → stripe[3] "CUR3001" → hash → stripe[7] ← different stripe, no contention!
Key Takeaway
Striped locking replaces one global lock with an array of N locks, where each key hashes to a stripe. Operations on different stripes run in parallel, reducing contention approximately N-fold. The hash function uses spread(hash) & (N-1) with N as a power of 2 for fast bitwise modulo. Unfair locks maximize throughput by allowing barging.
Use striped locks when ConcurrentHashMap's single-map atomicity is not enough: when you need atomic operations spanning multiple data structures (debit + audit log) or when you need cache stampede deduplication (100 threads miss the same key, only one loads from DB).
At National Bank of India, a global lock on the account service achieved 2,000 transactions per second. StripedLock(32) achieved 50,000 transactions per second, a 25x improvement. Cache stampede protection ensured that 500 concurrent requests for the same missing account resulted in only 1 DB query.
Remember one sentence: striped locking hashes keys to an array of N locks so different keys proceed in parallel, reducing contention N-fold for multi-structure atomic operations.
---