StampedLock 是不可重入锁,因其设计追求轻量高速且无状态,不记录持有线程与重入次数,同线程重复获取写锁会因 state 状态冲突自旋死锁;其 64 位 state 字段中低 7 位存读锁数、第 8 位为写锁标志、高位为版本号,写锁仅占 1 bit。

StampedLock 是不可重入锁,根本原因在于它的设计目标是轻量、高速、无状态,而不是提供线程安全的嵌套调用保障。它不记录持有锁的线程身份,也不维护重入计数,一旦同一线程重复获取写锁,就会因状态冲突直接陷入自旋等待,最终导致死锁。
底层状态结构不支持重入
StampedLock 用一个 64 位 long 类型的 state 字段编码全部锁状态:低 7 位表示读锁数量,第 8 位标记写锁占用,高位作为版本号。写锁只占 1 bit(即 WBIT = 1L ),值为 0 或 1 —— 它只表达“有没有被占用”,不区分“谁占的”或“占了几次”。
如果支持重入,就必须额外存储当前持有线程、维护 per-thread 计数器、在 unlock 时做减法判断是否真正释放……这些都会破坏其零内存开销、单原子操作的设计哲学。
写锁重入会卡死在线程自旋中
当一个线程已持有写锁(state & WBIT != 0),再次调用 writeLock() 或 tryWriteLock() 时:
立即学习“Java免费学习笔记(深入)”;
- 内部会不断尝试 CAS 修改
state,但因写位已被置 1,CAS 总失败; - 随后进入自旋逻辑(非阻塞式等待),持续抢锁、检查、重试;
- 由于没有线程中断响应机制,该线程将永远占用 CPU,无法让出资源;
- 其他等待该写锁的线程也被阻塞,整个锁系统实质瘫痪。
读锁升级写锁时的隐式重入陷阱
常见误用场景:线程先获取悲观读锁(readLock()),再调用 tryConvertToWriteLock(stamp) 升级 —— 表面看是“转换”,实则要求原 stamp 对应的状态必须未被修改,且写锁空闲。
若升级失败(比如已有其他线程持写锁),而代码未正确释放原读锁就再次尝试获取写锁,就可能造成:
– 同一线程既持有读锁又阻塞在写锁上;
– 其他线程因读锁未释放无法写入;
– 该线程又因写锁被自己(逻辑上)“占着”而无法前进 —— 形成跨模式的伪重入死锁。
乐观读 + 写操作混用引发数据校验失效
乐观读(tryOptimisticRead())本身不加锁,仅返回一个 stamp。若后续执行写操作前未校验(validate()),或校验后未做同步保护就修改共享变量,会导致:
- 多个线程同时通过乐观读拿到旧 stamp;
- 都验证成功(因尚未发生写),然后各自写入;
- 最终产生覆盖写、丢失更新等一致性问题;
- 为“修复”不一致,开发者可能加锁兜底,反而引入嵌套锁逻辑,放大重入风险。
它不是 bug,而是明确的设计取舍:用不可重入换极致性能,用无条件变量换结构简洁。用对场景,它是高并发读的利器;越界使用,就是定时死锁炸弹。


















