WMX · 随记
·Java· 3 分钟阅读

ReentrantLock:解锁必须覆盖异常路径

持锁过程中业务抛异常,后续线程就一直等待,通常是因为 unlock 没有放进 finally。同步代码同样需要异常安全。

Java 系列概览:类型与值、状态与资源、边界验证
Java 系列概览:类型与值、状态与资源、边界验证 点击图片查看大图 ↗

问题从哪里出现

持锁过程中业务抛异常,后续线程就一直等待,通常是因为 unlock 没有放进 finally。同步代码同样需要异常安全。

理解核心机制

lock 成功获得锁后,用 try/finally 包住受保护区域。tryLock 则先判断是否拿到锁,仅在成功时解锁。把持锁范围缩小,也能减少竞争和不必要的耦合。

动手做一个小实验

Java 17 或更新版本;将示例保存为 Demo.java,执行 javac Demo.java 后运行 java Demo。

Java10 行 · 可横向滚动
import java.util.concurrent.locks.ReentrantLock;
public class Demo {
    public static void main(String[] args) {
        var lock = new ReentrantLock();
        lock.lock();
        try { System.out.println("protected operation"); }
        finally { lock.unlock(); }
        System.out.println(lock.isLocked());
    }
}

适用边界与常见误区

同一把锁只保护遵守同一协议的访问。不要在持锁时调用不可控的慢网络请求,也不要误以为公平锁总能提高吞吐。

继续练习

在受保护区域主动抛异常,再从另一个线程尝试获取锁;测试 finally 是否确实覆盖所有出口。

参考资料

阅读相关官方文档或原始资料 ↗

← 返回文章归档