StampedLock是JDK8引入的高性能锁,通过乐观读机制提升读多写少场景吞吐量;其核心是用stamp验证读期间是否被写修改,失败则降级为悲观读重试,不支持重入且写优先,适用于轻量字段读取。

StampedLock 通过乐观读(optimistic read)机制,在无写竞争时避免加锁开销,显著提升高读低写的场景吞吐量。它不基于 AQS,而是用状态戳(stamp)实现无等待的读操作,是 JDK8 引入、专为读多写少优化的高性能锁工具。
乐观读的核心逻辑:先读再验
乐观读不是“加锁”,而是获取当前锁状态的时间戳(stamp)→ 读取共享数据 → 用 stamp 验证期间是否被写操作修改过。若未被修改,读结果有效;否则需降级为悲观读锁重试。
- 调用
tryOptimisticRead()返回一个 stamp:若锁处于写模式或正在写,返回 0;否则返回一个非零戳记 - 读取数据后,必须立即调用
validate(stamp)判断有效性——该方法仅做一次 volatile 读比较,开销极小 - 若
validate返回 false,说明读期间发生过写,此时应获取悲观读锁(readLock())重读
典型使用模式:读操作双路径保障
不能单独依赖乐观读,必须搭配悲观读作为 fallback。标准写法是“乐观读尝试 + 验证失败后阻塞重读”:
- 先
long stamp = lock.tryOptimisticRead() - 读取字段(如
int x = this.x),注意:只能读**final 或 volatile 字段**,或确保读操作本身不会因指令重排导致逻辑错误 - 调用
if (lock.validate(stamp))成立则直接返回结果 - 否则
stamp = lock.readLock(),再次读取,最后lock.unlockRead(stamp)
例如统计集合大小时,可先乐观读 size 字段,验证失败再加读锁遍历——多数情况下省去锁竞争。
写操作必须用 writeLock,且会阻塞所有乐观读验证
每次 writeLock() 成功后,内部 stamp 递增(偶数为读就绪态,奇数为写占用态)。因此:任何正在执行的写操作,都会让后续的 tryOptimisticRead() 返回 0,或使已获取的 stamp 在 validate() 时失败。
- 写锁是独占的,会阻塞新读锁请求,也会使所有未验证的乐观读“失效”
- 写操作结束后调用
unlockWrite(stamp),stamp 增加,新乐观读才可能成功 - 注意:写操作中不能嵌套调用乐观读验证,否则可能死锁或逻辑错乱
注意事项与适用边界
StampedLock 不是 ReentrantLock 或 ReadWriteLock 的通用替代品:
- 不支持重入:同一线程多次 readLock() 必须配对 unlockRead(),否则泄漏锁资源
- 无条件写优先:写锁饥饿问题比 ReadWriteLock 更明显,长期写竞争下读线程可能持续 fallback,吞吐反而下降
- 仅适合简单读场景:乐观读只适用于“读少量字段+快速验证”的操作;涉及复杂对象图遍历、IO 或耗时计算,应直接用悲观读锁
- 不能用于监听或条件等待:它不提供 newCondition(),也不支持 await/signal 语义
适合场景:缓存值访问、配置快照读取、计数器查询等读频次远高于写、且读逻辑轻量的系统模块。










