Appearance
StampedLock 怎么理解:乐观读、悲观读和写锁适合什么场景
StampedLock 经常会和:
synchronizedReentrantLockReentrantReadWriteLock
一起出现。
但它真正想解决的问题,并不是“再来一把更复杂的锁”,而是:
- 在读多写少场景里,把读开销再往下降一点
先说结论
StampedLock 最值得关注的能力是:
- 乐观读
- 悲观读
- 写锁
它更适合:
- 读远多于写
- 允许先读后校验
- 对性能比较敏感的共享状态读取
但它也有明显边界:
- 使用复杂度更高
- 不是可重入锁
- 用错更容易出 bug
一、它和读写锁的差别在哪里
传统读写锁的思路是:
- 读读可以并行
- 读写互斥
- 写写互斥
StampedLock 在这个基础上又多了一层:
- 乐观读
也就是说,它允许某些读操作先不真正加悲观读锁,而是:
- 先拿一个版本戳
- 读取数据
- 再校验读期间有没有写发生
二、乐观读怎么理解
可以先粗略理解成:
- 先假设这段时间没人改数据
- 读完后再验证
如果验证通过:
- 本次读可以认为有效
如果验证失败:
- 再退回悲观读重来
这在读多写少场景里很有吸引力,因为:
- 大量读取不一定都要走真正的锁竞争
三、它什么时候比读写锁更有优势
如果一个共享对象满足:
- 读非常频繁
- 写很少
- 读取逻辑很短
那乐观读带来的收益会比较明显。
典型场景例如:
- 坐标位置读取
- 运行状态快照
- 配置快照读取
四、为什么它不是所有场景都适合
1. 它不是可重入锁
这点非常重要。
如果你按 ReentrantLock 的思路去写,很容易踩坑。
2. API 使用复杂度更高
尤其是:
- 乐观读校验
- 锁升级
- 锁释放时机
如果代码团队对并发模型不够熟,反而更容易出错。
3. 不是所有读多写少都值得上它
很多普通业务里,ReentrantReadWriteLock 已经足够了。
五、一个更实际的选择顺序
1. 普通互斥逻辑
先看:
synchronizedReentrantLock
2. 明确读多写少
再看:
ReentrantReadWriteLock
3. 读非常频繁,且你能接受更复杂的并发实现
再考虑:
StampedLock
六、几个容易踩的坑
1. 把它当成读写锁平替
它们有交集,但设计重点并不完全相同。
2. 乐观读后忘记校验
那就失去了安全边界。
3. 复杂业务逻辑里滥用乐观读
如果读逻辑太长、太复杂,乐观读失败率可能很高,收益也会下降。
一句话总结
StampedLock 的价值不在于“新锁”,而在于它为读多写少场景提供了乐观读这条更轻的路径。
但它更像进阶工具,不是所有团队、所有业务都需要优先使用。