Advantages of StampedLock
ReentrantLock does not support read-write separation. Although ReentrantReadWriteLock allows for read-write separation, it requires that no other read or write locks are active when acquiring a write lock, wich results in a pessimistic approach. In scenarios where there are many read operations and few writes, threads may experience starvation.
Starvation: ReentrantReadWriteLock enables read-write separation, but to acquire a read lock, it must ensure that no other read or write lock are active. When there are many read operations, acquiring a write lock becomes difficult becuase read locks may be continuously present. This makes it impossible to obtain a write lock.
In such cases, Java 1.8 introduced a new locking mechanism called StampedLock.
Usage
StampedLock offers three modes (write, read, optimistic read) based on CLH Lock.
(1) Writing: writeLock is an exclusive lock and also a pessimistic lock.
(2) Reading: readLock is a pessimistic lock.
(3) Optimistic Reading: the tryOptimisticRead method returns a non-zero stamp, which can only be obtained if the current synchronization state is not occupied by a write mode. Optimistic reading is used for short read operations to reduce contention and improve throughput.
When using it, it is common to read and store a copy for comparison. Below is a code implementation of these locking mechanisms.
Official example:
class Point {
private double x, y;
private final StampedLock sl = new StampedLock();
void move(double deltaX, double deltaY) { // an exclusively locked method
long stamp = sl.writeLock();
try {
x += deltaX;
y += deltaY;
} finally {
sl.unlockWrite(stamp);
}
}
double distanceFromOrigin() { // A read-only method
long stamp = sl.tryOptimisticRead();
double currentX = x, currentY = y;
if (!sl.validate(stamp)) {
stamp = sl.readLock();
try {
currentX = x;
currentY = y;
} finally {
sl.unlockRead(stamp);
}
}
return Math.sqrt(currentX * currentX + currentY * currentY);
}
void moveIfAtOrigin(double newX, double newY) { // upgrade
// Could instead start with optimistic, not read mode
long stamp = sl.readLock();
try {
while (x == 0.0 && y == 0.0) {
long ws = sl.tryConvertToWriteLock(stamp);
if (ws != 0L) {
stamp = ws;
x = newX;
y = newY;
break;
}
else {
sl.unlockRead(stamp);
stamp = sl.writeLock();
}
}
} finally {
sl.unlock(stamp);
}
}
}
The scheduling strategy of StampedLock treats read and write operations fairly. All try methods attempt to succeed, but they may fail. This class does not directly implement Lock or ReadWriteLock methods; instead, it is implemented as a standalone class. Additionally, a StampedLock can provide subsets of its full functionality through asReadLock, asWriteLock, and asReadWriteLock methods.