Mastering Java ReadWriteLock and StampedLock: When and How to Use Them
This article explains Java's ReadWriteLock and the newer StampedLock, compares their performance, shows practical code examples for read, write, optimistic reads, and lock conversion, and highlights important limitations such as lack of reentrancy and Condition support.
Overview
Java’s ReadWriteLock allows many concurrent readers but only one writer, which is ideal when reads vastly outnumber writes. Since Java 8, StampedLock adds an optimistic read mode and finer‑grained control, reducing contention for short read‑only sections.
ReadWriteLock Example
public class ReadWriteLockTest {
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
private final Lock writeLock = rwLock.writeLock();
private int count = 0;
public void read() {
readLock.lock();
try {
System.out.printf("%s - read: %s%n", Thread.currentThread().getName(), count);
} finally {
readLock.unlock();
}
}
public void write(int value) {
writeLock.lock();
try {
count = value;
System.out.printf("%s - write: %s%n", Thread.currentThread().getName(), count);
} finally {
writeLock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
ReadWriteLockTest instance = new ReadWriteLockTest();
Runnable readTask = () -> {
for (int i = 0; i < 5; i++) {
instance.read();
try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
}
};
Runnable writeTask = () -> {
for (int i = 0; i < 5; i++) {
instance.write(i * 10);
try { TimeUnit.MILLISECONDS.sleep(200); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
}
};
Thread r1 = new Thread(readTask, "R-1");
Thread r2 = new Thread(readTask, "R-2");
Thread w1 = new Thread(writeTask, "W-1");
r1.start(); r2.start(); w1.start();
r1.join(); r2.join(); w1.join();
System.out.printf("final result: %s%n", instance.count);
}
}When the read‑to‑write ratio reaches tens of thousands, acquiring a lock for every read becomes a bottleneck.
StampedLock Modes
writeLock() – exclusive lock, returns a stamp used for unlockWrite(stamp).
readLock() – shared lock, returns a stamp for unlockRead(stamp).
tryOptimisticRead() – returns a non‑zero stamp only if no thread holds the write lock. The stamp can be validated with validate(stamp); if validation fails, fall back to a regular read lock.
StampedLock Code Samples
Read Lock
private final StampedLock lock = new StampedLock();
private Object shared = "init data";
public Object read() {
long stamp = lock.readLock();
try {
return shared;
} finally {
lock.unlockRead(stamp);
}
}Optimistic Read
public Object optimisticRead() {
long stamp = lock.tryOptimisticRead();
Object value = shared;
if (!lock.validate(stamp)) {
stamp = lock.readLock();
try {
value = shared;
} finally {
lock.unlockRead(stamp);
}
}
return value;
}Write Lock
public void write(Object data) {
long stamp = lock.writeLock();
try {
shared = data;
} finally {
lock.unlockWrite(stamp);
}
}Lock Conversion (optimistic → read → write)
public void convertAndWrite(Object newData) {
long stamp = lock.tryOptimisticRead();
Object current = shared;
if (!lock.validate(stamp)) {
stamp = lock.readLock();
try {
current = shared;
} finally {
lock.unlockRead(stamp);
}
}
// Attempt to upgrade to a write lock
stamp = lock.tryConvertToWriteLock(stamp);
if (stamp == 0L) { // upgrade failed
lock.unlockRead(stamp);
stamp = lock.writeLock();
}
try {
shared = newData;
System.err.printf("final data: %s%n", shared);
} finally {
if (StampedLock.isWriteLockStamp(stamp)) {
lock.unlockWrite(stamp);
} else {
lock.unlockRead(stamp);
}
}
}Performance Comparison
Benchmarks (one‑read‑one‑write, two‑read‑one‑write, three‑read‑one‑write, two‑read‑two‑write) show that as the read‑to‑write ratio grows, StampedLock outperforms ReadWriteLock because optimistic reads avoid lock acquisition overhead.
Caveats
No reentrancy – a thread cannot acquire the same StampedLock again.
No Condition support – you cannot create condition objects for waiting.
Lock conversion risks – improper use of tryConvertToWriteLock can lead to deadlocks.
These limitations should be considered before adopting StampedLock in production code.
Environment
All examples were compiled and run on Java 21. StampedLock is available since Java 8.
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.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
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.
