在 finally 块中安全释放 reentrantreadwritelock,必须确保只释放当前线程持有的锁且不重复释放;需严格区分读锁与写锁并匹配释放;推荐用布尔标志或 try-with-resources 封装来避免非法释放。

在 finally 块中安全释放 ReentrantReadWriteLock,核心是:**必须确保只释放当前线程持有的锁,且不能重复释放或释放未获取的锁**。直接调用 unlock() 而不检查持有状态,极易引发 IllegalMonitorStateException。
区分读锁与写锁,按获取路径对应释放
ReentrantReadWriteLock 提供独立的读锁(readLock())和写锁(writeLock()),二者互不影响。释放时必须严格匹配:
- 用
readLock().lock()获取的,只能用readLock().unlock()释放 - 用
writeLock().lock()获取的,只能用writeLock().unlock()释放 - 不可混用,例如不能用读锁对象去释放写锁获得的持有权
避免在 finally 中无条件 unlock() —— 先确认是否已成功加锁
常见错误是把 lock() 放在 try 外、unlock() 放在 finally 内,但若加锁失败(如被中断、超时),unlock() 会抛异常:
// ❌ 危险写法
lock.writeLock().lockInterruptibly(); // 可能抛 InterruptedException
// ... 业务逻辑
} finally {
lock.writeLock().unlock(); // 若上面没成功加锁,这里直接报错
}
✅ 正确做法:用布尔标志记录是否已持锁,仅在确认持有后才释放:
boolean isWriteLocked = false;
try {
lock.writeLock().lockInterruptibly();
isWriteLocked = true;
// ... 执行写操作
} finally {
if (isWriteLocked) {
lock.writeLock().unlock();
}
}
使用 try-with-resources 封装(推荐,更简洁可靠)
可自定义一个支持自动释放的 AutoCloseableLock,将锁封装为资源:
public class AutoCloseableWriteLock implements AutoCloseable {
private final ReentrantReadWriteLock lock;
private boolean locked = false;
public AutoCloseableWriteLock(ReentrantReadWriteLock lock) {
this.lock = lock;
}
public void lock() throws InterruptedException {
lock.writeLock().lockInterruptibly();
locked = true;
}
@Override
public void close() {
if (locked) {
lock.writeLock().unlock();
locked = false;
}
}
}
使用方式(自动保证释放):
try (AutoCloseableWriteLock l = new AutoCloseableWriteLock(lock)) {
l.lock();
// ... 写操作
} // 自动 unlock,无需 finally
注意可重入性与计数 —— unlock() 必须与 lock() 次数匹配
ReentrantReadWriteLock 是可重入的,每次 lock() 都会增加持有计数,每次 unlock() 减一;只有计数归零才真正释放。因此:
- 若同一线程多次获取同一把锁(如递归写操作),需调用相同次数的
unlock() - 不要因“已经 unlock 过”就跳过释放 —— 应严格配对,否则可能导致锁永久占用
- 可通过
getReadHoldCount()或getWriteHoldCount()调试验证持有状态(仅限开发/测试)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











