邮戳锁- StampedLock
ReentrantLock 不管公平锁还是非公平锁都是独占锁,所以有了 ReentrantReadWriteLock 读写分离的锁
ReentrantReadWriteLock 性能已经很好了,读读可以并发,但是还不够快,这就是 StampedLock 的产生背景
StampedLock 还可以乐观读进一步提升性能,乐观读就是无锁的状态了
本章只分析 StampedLock,AQS 从入门到精通
使用示例
import java.util.concurrent.locks.StampedLock;
public class StampedLockExample {
private int sharedData = 0; // 保护的数据
private final StampedLock lock = new StampedLock();
// 乐观读(不阻塞,需要验证)
public int optimisticRead() {
long stamp = lock.tryOptimisticRead(); // 乐观读
int currentValue = sharedData;
if (!lock.validate(stamp)) { // 如果验戳失败,要升级为读锁
stamp = lock.readLock(); // 锁升级
try {
currentValue = sharedData; // 要重新读取一次数据,防止数据已经被修改
} finally {
lock.unlockRead(stamp); // 释放锁(戳)
}
}
return currentValue;
}
// 共享读(阻塞式)
public int sharedRead() {
long stamp = lock.readLock();
try {
return sharedData;
} finally {
lock.unlockRead(stamp); // 释放锁(戳)
}
}
// 悲观写(独占锁)
public void pessimisticWrite(int newValue) {
long stamp = lock.writeLock();
try {
sharedData = newValue;
} finally {
lock.unlockWrite(stamp); // 释放锁(戳)
}
}
public static void main(String[] args) {
StampedLockExample example = new StampedLockExample();
// 写线程
new Thread(() -> {
for (int i = 1; i <= 5; i++) {
example.pessimisticWrite(i);
System.out.println("写入数据: " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}).start();
// 读线程(乐观读)
new Thread(() -> {
for (int i = 0; i < 5; i++) {
int value = example.optimisticRead();
System.out.println("乐观读取: " + value);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}).start();
// 读线程(共享读)
new Thread(() -> {
for (int i = 0; i < 5; i++) {
int value = example.sharedRead();
System.out.println("共享读取: " + value);
try {
Thread.sleep(400);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}).start();
}
}
缺点
- 不支持条件变量,写锁也不支持
- 不可重入
适用场景
StampedLock 最适合读多写少的场景,特别是当:
- 读操作远多于写操作
- 读操作可以容忍短暂的数据不一致(乐观读)
- 需要比 ReentrantReadWriteLock 更高的吞吐量

浙公网安备 33010602011771号