StampedLock 通过 stamp 实现读写分离,支持写锁、悲观读锁、乐观读锁三种模式;乐观读需 validate 验证后失败转悲观读,不可直接升级写锁;写锁可降级为悲观读锁,但需手动释放再获取;悲观读锁禁止升级写锁,必须先释放再抢锁。

StampedLock 的核心设计是通过“戳记(stamp)”来区分不同锁状态,它不基于传统 AQS 队列,而是用 CAS + 自旋 + 状态位控制实现高性能读写分离。它支持三种模式:写锁、悲观读锁、乐观读锁。三者之间不是“自动转换”,而是需要手动配合 stamp 值进行显式判断与升级/降级操作,关键在于理解 stamp 的语义和使用边界。
乐观读锁 → 悲观读锁:验证失败后安全升级
乐观读不加锁,仅记录当前版本戳;后续需用 validate(stamp) 校验是否被写操作修改过。若校验失败(返回 false),说明数据可能已变更,此时应放弃乐观路径,转为获取悲观读锁保证一致性。
- 调用
tryOptimisticRead()获取初始 stamp - 读取共享变量(注意:必须是无副作用的纯读取)
- 立即调用
validate(stamp);若返回 false,说明期间发生过写操作 - 此时调用
readLock()获取悲观读锁,再重新读取数据 - 最后务必调用
unlockRead()释放悲观读锁
乐观读锁 → 写锁:不能直接升级,必须先释放再获取
StampedLock 不支持从乐观读直接升级到写锁(即“锁升级”被禁止),这是为避免死锁。乐观读本身无锁持有,不存在“持有读锁再去抢写锁”的竞争逻辑,但若业务需要“读-改-写”,必须走“验证 → 释放 → 重试”流程:
- 先用乐观读尝试读取并 validate 成功,则可安全执行后续逻辑
- 若需修改,必须先放弃乐观假设,调用
writeLock()获取写锁(会阻塞其他读写) - 注意:
writeLock()不依赖之前乐观读的 stamp,它是独立获取的全新 stamp - 写完后调用
unlockWrite(stamp),stamp 来自 writeLock() 返回值
写锁 → 悲观读锁:可降级,但需主动释放再获取
持有写锁时,当前线程独占访问权,可安全降级为悲观读锁(即释放写权限,转为共享读权限),但 StampedLock 不提供原子降级 API,必须手动完成:
立即学习“Java免费学习笔记(深入)”;
- 持有写锁期间,调用
unlockWrite(writeStamp)释放写锁 - 再调用
readLock()获取悲观读锁(此时其他线程可能已插入写操作) - 若需确保降级后仍保持数据一致,应在写锁内完成所有修改,并在 unlockWrite 后尽快进入 readLock,或结合应用层逻辑控制时序
悲观读锁 → 写锁:禁止升级,必须先释放再抢写锁
这是最易出错的场景。悲观读锁是可重入的共享锁,多个线程可同时持有;若允许其直接升级为写锁,将导致死锁(其他读线程阻塞写锁,而该线程又持着读锁不放)。因此:
- 持有
readLock()时,绝不可调用writeLock()—— 这会导致永久阻塞甚至死锁 - 正确做法是:先
unlockRead(readStamp),再调用writeLock() - 注意释放读锁后,数据可能已被他人修改,所以写前通常需重新校验或重读


















