stampedlock 的乐观读是轻量校验而非加锁,需严格遵循“读前 stamp、读后立即 validate”,仅读 volatile/final 字段,禁用耗时操作,失败必降级为悲观读并正确释放锁;写操作须独占且显式释放,高冲突、耗时读、非 volatile 字段、读写依赖等场景不适用。

StampedLock 的乐观读不是“开了个锁”,而是用一次轻量校验代替加锁,适合读多写少、读操作极快的场景。关键不在“怎么用”,而在“怎么不踩坑”——漏掉 validate、中间插入耗时操作、或读了非 volatile 字段,都会让性能不升反降,甚至读到脏数据。
乐观读必须严格遵循“读前获取 stamp,读后立即 validate”
调用 tryOptimisticRead() 返回一个 stamp(本质是状态快照),它不阻塞、不加锁,但也不提供任何同步保证。紧接着必须:
- 只读取 volatile 或 final 字段(普通字段无法保证可见性)
- 不做任何可能触发 GC、线程调度或 I/O 的操作(比如日志、空循环、方法调用)
- validate(stamp) 必须紧跟在读取语句之后,中间不能穿插计算或赋值逻辑
验证失败必须降级为悲观读,且要确保释放锁
validate 返回 false,说明读期间有写操作发生,此时不能重试乐观读,也不能直接返回旧值——必须升级为 readLock() 重新读取:
- 用 try-finally 包裹读操作,防止异常导致锁未释放
- 不能在持有 readLock 时再调用 tryOptimisticRead(),会破坏锁状态
- 读完立即 unlockRead(stamp),避免锁泄漏影响后续线程
写操作必须独占 + 显式释放,且不能和乐观读并发干扰
writeLock 是排他锁,会阻塞所有乐观读的 validate(即一旦 writeLock 被获取,之前所有 tryOptimisticRead 得到的 stamp 都会失效):
- 写入前必须调用 writeLock() 获取 stamp
- 修改完成后,必须在 finally 块中调用 unlockWrite(stamp)
- 禁止同一线程重复获取 writeLock(StampedLock 不支持重入,否则死锁)
- 不要在写操作中嵌套读逻辑,尤其避免在 writeLock 持有期间调用其他含乐观读的方法
哪些场景不适合乐观读?
盲目套用反而引入 bug 或拖慢性能:
- 读操作本身耗时(如含复杂计算、对象克隆、JSON 序列化)——validate 失败后前面工作全白费
- 共享字段不是 volatile 或 final——validate 成功也无法保证看到最新值
- 需要基于读结果做条件判断再写入(例如“如果 count
- 写操作频繁(冲突率高)——validate 失败率高,频繁降级使乐观读失去意义
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











