StampedLock 通过乐观读避免读写互斥,适合读多写少、读操作轻量的场景;它基于CAS和状态戳实现,支持乐观读、悲观读、写锁三种模式,不支持重入和中断。

StampedLock 通过“乐观读”避免读操作阻塞写操作,适合读多写少且读操作耗时短的场景。它不基于 AQS,而是用 CAS + 状态戳(stamp)实现,支持三种模式:乐观读、悲观读、写锁。
乐观读的核心逻辑与使用步骤
乐观读不是真正的锁,而是先尝试无锁读取,再用 stamp 验证数据是否被写入修改。若未被修改,直接返回结果;否则退化为悲观读锁重试。
- 调用 tryOptimisticRead() 获取当前 stamp(可能为 0,表示有写操作正在进行)
- 执行读操作(必须是无副作用、可重入的纯读取,如取字段值、计算表达式)
- 调用 validate(stamp) 检查 stamp 是否仍有效 —— 若返回 true,说明读期间无写入,结果可信;若 false,需加悲观读锁重试
典型使用模板(带重试)
以下是一个安全读取共享变量的常见写法:
long stamp = sl.tryOptimisticRead();
int current = x; // 读共享变量
if (!sl.validate(stamp)) {
// 乐观读失败,升级为悲观读
stamp = sl.readLock();
try {
current = x;
} finally {
sl.unlockRead(stamp);
}
}
// 此时 current 是一致的值
注意:乐观读期间不能调用可能阻塞或依赖外部状态的方法(如 I/O、synchronized 块、其他锁),否则 validate 失效后重试成本高,甚至引发逻辑错误。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
写锁与读锁的协作要点
StampedLock 的写锁是独占的,会阻塞所有读(包括乐观读和悲观读);悲观读锁是共享的,但会阻塞写锁。关键约束:
- 写锁必须用 writeLock() / unlockWrite(stamp) 成对使用
- 悲观读锁必须用 readLock() / unlockRead(stamp) 成对使用
- 不可在持有写锁时再获取读锁(会死锁),也不建议在读锁中嵌套写锁
- stamp 是一次性凭证,不可复用;每次 lock/unlock 都生成新 stamp
适用场景与避坑提醒
StampedLock 适合:读频次远高于写、读逻辑简单快速、能容忍偶尔重试 的场景,比如配置缓存、统计计数器、只读元数据快照。
慎用情况:
- 读操作包含复杂计算或外部调用(重试开销大)
- 需要锁重入(StampedLock 不支持重入,重复 lock 会阻塞)
- 要求严格公平性或中断响应(它不支持 lockInterruptibly 或条件队列)
- 与 synchronized 或 ReentrantLock 混用时未考虑锁粒度与可见性(仍需 volatile 或 final 保证字段初始化可见)

















