Java StampedLock的乐观读失败后转换为悲观读锁
Java 并发包中的 StampedLock 提供了一种乐观读机制,通常比标准的 ReentrantReadWriteLock 更快。它的核心思路是:先试着读数据,如果发现数据正在被修改,再升级为悲观读锁。
核心操作流程
乐观读不会阻塞写线程,这非常适合读多写少且读操作很快的场景。当乐观读校验失败时,必须转换为悲观读锁以保证数据一致性。
以下是实现这一机制的标准步骤:
- 创建
StampedLock实例。 - 调用
tryOptimisticRead()方法获取一个版本戳记(stamp)。 - 复制 共享变量到局部方法变量中。注意:不要在校验前直接使用共享变量。
- 调用
validate(stamp)方法检查在读取期间是否有写操作发生。 - 判断 返回结果:
- 如果返回
true,说明没有写操作发生,直接使用局部变量。 - 如果返回
false,说明数据脏了,执行 升级逻辑。
- 如果返回
乐观读失败后的转换步骤
当 validate 返回 false 时,意味着在你读取数据的过程中,有线程修改了数据。此时必须放弃乐观读,转为悲观读锁。请按以下步骤执行:
- 调用
readLock()方法获取悲观读锁。此操作会阻塞,直到获取到锁。 - 重新复制 共享变量到局部变量。因为之前的数据已经过时,必须重新读取。
- 调用
unlockRead(stamp)释放悲观读锁。注意:这里的stamp是readLock()返回的新戳记,不是乐观读的戳记。 - 使用 最新的局部变量进行后续业务逻辑处理。
代码实现示例
以下代码演示了一个典型的“观察者”模式,使用乐观读,并在失败时自动降级。
import java.util.concurrent.locks.StampedLock;
public class Point {
private double x, y;
private final StampedLock sl = new StampedLock();
// 写操作(互斥)
void move(double deltaX, double deltaY) {
long stamp = sl.writeLock();
try {
x += deltaX;
y += deltaY;
} finally {
sl.unlockWrite(stamp);
}
}
// 读操作(乐观读 -> 悲观读转换)
double distanceFromOrigin() {
// 1. 尝试获取乐观读锁
long stamp = sl.tryOptimisticRead();
// 2. 读取数据到局部变量
double currentX = x;
double currentY = y;
// 3. 校验 stamp 是否有效
if (!sl.validate(stamp)) {
// 4. 校验失败,获取悲观读锁
stamp = sl.readLock();
try {
// 5. 重新读取数据
currentX = x;
currentY = y;
} finally {
// 6. 释放悲观读锁
sl.unlockRead(stamp);
}
}
// 7. 计算并返回结果
return Math.sqrt(currentX * currentX + currentY * currentY);
}
}
逻辑流程图
下图清晰地描述了从乐观读开始,到校验失败后切换为悲观读锁的完整判断路径。
graph TD
Start[开始] --> GetStamp[调用 tryOptimisticRead]
GetStamp --> CopyVars[复制变量 x, y]
CopyVars --> Check{validate stamp ?}
Check -->|true| Calc[计算结果]
Check -->|false| GetReadLock[调用 readLock]
GetReadLock --> CopyVarsAgain[重新复制变量 x, y]
CopyVarsAgain --> Unlock[调用 unlockRead]
Unlock --> Calc
Calc --> End[结束]
关键注意事项
在编写转换逻辑时,请务必遵守以下规范以避免死锁或数据错误:
- 区分 Stamp:乐观读的
stamp和悲观读的stamp是不同的变量。释放锁时,必须使用readLock()返回的那个stamp。 - 重读变量:进入
if (!sl.validate(stamp))代码块后,切勿使用之前tryOptimisticRead期间读取的局部变量。必须重新从主内存中读取共享变量。 - Finally 释放:悲观读锁的释放必须放在
finally块中,确保代码异常时锁也能被正确释放。

暂无评论,快来抢沙发吧!