readwritelock 的写锁是可重入的,仅限同一线程在已持有锁前提下重复获取;每次 lock() 使 state 低 16 位加 1,需对应次数 unlock() 才完全释放。

Java 中 ReadWriteLock 的写锁(WriteLock)是可重入的,但重入行为仅限于**同一个线程**,且必须在已持有该写锁的前提下才能再次获取——这与 ReentrantLock 的重入逻辑一致。它不是“任意线程都能重入”,而是“当前持有者可重复加锁”。
写锁重入的基本规则
写锁本质上是独占锁,其重入性体现在:同一线程可多次调用 lock() 而不被阻塞,每次加锁都会使内部计数器+1;对应地,必须调用相同次数的 unlock() 才能真正释放锁。
- 不同线程尝试获取已被占用的写锁 → 阻塞等待(或 tryLock 返回 false)
- 同一线程在未释放写锁前再次 lock() → 成功,state 低 16 位递增
- 同一线程 unlock() 次数少于 lock() 次数 → 锁仍被持有,其他线程无法获取
- unlock() 次数等于 lock() 次数 → 写锁完全释放,state 低 16 位归零
典型测试代码与关键观察点
以下是一个验证写锁重入性的最小可行示例:
// 注意:必须使用同一个 WriteLock 实例,且在同一线程内操作
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();<br>Lock writeLock = rwLock.writeLock();<br><br>new Thread(() -> {<br> writeLock.lock(); // 第一次获取<br> System.out.println("第1次加锁成功");<br> writeLock.lock(); // 第2次重入(同一线程)→ 不阻塞<br> System.out.println("第2次重入成功");<br> writeLock.unlock(); // 仅释放1次<br> System.out.println("释放1次后,锁仍被持有");<br> // 此时其他线程调用 writeLock.lock() 仍会被阻塞<br> writeLock.unlock(); // 完全释放<br> System.out.println("写锁已释放");<br>}).start();
重入失败的常见误判场景
容易误以为“写锁不可重入”的情况,往往源于对线程边界或锁实例的混淆:
-
跨线程调用:线程A持有写锁,线程B调用
lock()→ 必然阻塞,这不是重入失败,而是正常互斥 -
混用不同锁实例:创建多个
ReentrantReadWriteLock对象 → 各自独立计数,无法构成重入关系 - 未配对 unlock:只调用一次 unlock 却 lock 了两次 → 锁未真正释放,后续获取会失败,属使用错误而非机制缺陷
- 读锁干扰判断:写锁被持有时,任何读锁请求都会被阻塞;若误测“读锁能否与写锁共存”,会得出错误结论
底层状态如何体现重入次数
ReentrantReadWriteLock 基于 AQS 的 state(int)字段实现状态管理:
- 低 16 位(
state & 0xFFFF)记录写锁重入次数 - 高 16 位记录读锁持有线程数
- 例如:
state = 0x00000003表示写锁被同一线程获取了 3 次 - 每次
lock()触发 CAS 更新 state,校验当前持有者是否为当前线程
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











