StampedLock 通过乐观读(tryOptimisticRead + validate)实现无锁读,失败后降级为悲观读;写操作必须用 writeLock 并显式 unlockWrite;不支持重入和条件等待,需严格遵循“尝试→验证→重试”三步模式。

StampedLock 通过乐观读避免读操作阻塞,适合读多写少场景。它不直接继承 Lock 接口,而是用“戳记(stamp)”区分锁状态,读操作先尝试无锁访问,失败再降级为悲观读,从而减少线程等待。
理解乐观读的核心逻辑
乐观读不是加锁,而是记录当前锁状态的一个“时间戳”(stamp)。调用 tryOptimisticRead() 获取 stamp,随后读取共享数据,再用 validate(stamp) 核查期间是否有写操作发生。只要 validate 返回 true,说明读取过程没被写干扰,结果可信;否则需重新加锁读取。
- 乐观读全程无同步开销,适用于数据变动不频繁、读取逻辑轻量的场景
- validate 检查的是写锁是否在 stamp 获取后被获取过,不是精确到每次写操作,但足够保证一致性
- 不能在乐观读验证通过前修改数据,也不能把乐观读结果用于后续带条件的写决策(可能已过期)
正确使用乐观读的三步模式
典型用法是“尝试→验证→重试”,需严格遵循顺序:
- 第一步:调用 long stamp = lock.tryOptimisticRead() 获取初始戳记
- 第二步:读取变量(如 int value = this.value),注意不要调用可能触发写或阻塞的方法
- 第三步:立即调用 if (lock.validate(stamp)) 判断是否有效;若为 false,则转为悲观读:stamp = lock.readLock(); try { ... } finally { lock.unlockRead(stamp); }
写操作必须用 writeLock 配合 stamp 管理
写入时不能忽略 stamp 的释放,否则会造成锁泄漏:
立即学习“Java免费学习笔记(深入)”;
- 写操作必须用 long stamp = lock.writeLock() 获取写锁
- 修改完数据后,必须显式调用 lock.unlockWrite(stamp)
- 可配合 try-finally 或 try-with-resources(需封装为 AutoCloseable)确保释放
- 注意:writeLock 是排他锁,会阻塞所有读(包括乐观读),但只在真正冲突时才生效
常见误用与规避建议
StampedLock 功能强大但易出错,需避开几个典型陷阱:
- 不要在乐观读验证通过前执行耗时计算或 I/O——一旦 validate 失败,这些工作就白做了
- 避免嵌套使用乐观读和悲观读,尤其不要在持有 readLock 时再调用 tryOptimisticRead()
- StampedLock 不支持重入,同一个线程重复获取同一类型锁会导致死锁或异常
- 不适用于需要条件等待的场景(如 await/signal),它没有 Condition 支持,应改用 ReentrantLock


















