StampedLock
是 Java 8 引入的一种新的锁机制,旨在提供更高的并发性能,特别是在读多写少的场景中。它是 ReentrantReadWriteLock
的增强版,通过引入“戳记(Stamp)”概念,提供了更灵活的锁控制方式。
核心特点
三种模式
写锁(Write Lock)
独占锁,类似于
ReentrantReadWriteLock
的写锁;同一时刻只有一个线程可以获取写锁。
读锁(Read Lock)
共享锁,类似于
ReentrantReadWriteLock
的读锁;多个线程可以同时获取读锁。
乐观读(Optimistic Read)
一种无锁的读模式,允许在不阻塞写锁的情况下进行读操作;
在读操作完成后,需要验证戳记(Stamp)以确保数据的一致性。
戳记(Stamp)
每次获取锁时都会返回一个戳记(long 类型的值);
戳记用于后续的锁释放或验证操作。
主要方法
写锁
long writeLock()
:获取写锁,返回戳记;void unlockWrite(long stamp)
:释放写锁,需要传入对应的戳记。
读锁
long readLock()
:获取读锁,返回戳记;void unlockRead(long stamp)
:释放读锁,需要传入对应的戳记。
乐观读
long tryOptimisticRead()
:尝试获取乐观读锁,返回戳记;boolean validate(long stamp)
:验证戳记是否有效(即在此期间是否有写操作发生)。
锁转换
long tryConvertToWriteLock(long stamp)
:尝试将读锁转换为写锁;long tryConvertToReadLock(long stamp)
:尝试将写锁转换为读锁。
优点
高性能:乐观读模式避免了读操作与写操作的冲突,显著提高了读多写少场景的性能;
灵活性:支持锁的升级(读锁转写锁)和降级(写锁转读锁)。
缺点
复杂性:使用
StampedLock
需要更复杂的代码逻辑,尤其是乐观读模式;不支持条件变量:
StampedLock
不支持类似Condition
的条件变量,因此不能用于需要等待通知的场景;无重入性:
StampedLock
不是可重入锁,因此需要避免死锁。
示例代码
import java.util.concurrent.locks.StampedLock;
public class StampedLockExample {
private final StampedLock stampedLock = new StampedLock();
private int value = 0;
// 写操作
public void write(int newValue) {
long stamp = stampedLock.writeLock(); // 获取写锁
try {
value = newValue;
} finally {
stampedLock.unlockWrite(stamp); // 释放写锁
}
}
// 读操作(悲观读)
public int read() {
long stamp = stampedLock.readLock(); // 获取读锁
try {
return value;
} finally {
stampedLock.unlockRead(stamp); // 释放读锁
}
}
// 读操作(乐观读)
public int optimisticRead() {
long stamp = stampedLock.tryOptimisticRead(); // 尝试乐观读
int currentValue = value;
if (!stampedLock.validate(stamp)) { // 验证戳记
stamp = stampedLock.readLock(); // 获取读锁
try {
currentValue = value;
} finally {
stampedLock.unlockRead(stamp); // 释放读锁
}
}
return currentValue;
}
public static void main(String[] args) {
StampedLockExample example = new StampedLockExample();
// 写线程
new Thread(() -> {
for (int i = 0; i < 10; i++) {
example.write(i);
System.out.println("Write: " + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}).start();
// 读线程
new Thread(() -> {
for (int i = 0; i < 10; i++) {
int result = example.optimisticRead();
System.out.println("Read: " + result);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}).start();
}
}