记一次ReentrantLock和java.lang.IllegalMonitorStateException异常

结论在前

ReentrantLock的锁对象,在释放锁之前,必须确保已上锁(锁的state=1)。在未上锁状态下,不能释放锁,若强行释放锁,将报IllegalMonitorStateException异常。

未上锁状态:包括主动不上锁或其他异常导致上锁不成功
措施:为避免次异常,养成良好的编程习惯,将上锁代码放在所有可能异常代码之前,或者简单粗暴的将上锁代码放在方法的第一行!


项目场景:

某金融系统在运行时,通过查看日志,发现报了一个IllegalMonitorStateException运行时异常


问题描述

在执行某方法时,先后连续报了java.lang.NullPointerExceptionjava.lang.IllegalMonitorStateException异常。经检查,报错的方法逻辑朴实无华,唯一就是用到了一个ReentrantLock。

异常代码类似如下:

	private static Logger logger = LoggerFactory.getLogger(TestService.class);
    private static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) {
        try {
            String name = null;
            String[] arr = name.split(","); // 1、此处将触发空指针异常
            lock.lock();
        } catch (Exception e) {
            logger.error("ERROR : ", e); // 2、打印异常
        } finally {
            lock.unlock(); // 3、释放锁
        }
        System.out.println("【 excute successfully 】");
    }

java.lang.IllegalMonitorStateException异常的API解释:
线程尝试等待一个对象的监视器或者去通知其他正在等待这个对象监视器的线程时,但是没有拥有这个监视器的所有权,就会抛出这个异常

debug截图:
在这里插入图片描述
注:由于空指针导致未成功上锁(锁的状态是0),catch完异常后,直接执行finally代码块中的释放锁,报异常(未上锁,不能释放锁,不然异常)

运行控制台截图:
在这里插入图片描述


原因分析:

提示:针对ReentrantLock的对象lock,如果上锁,和释放锁不是在同一个线程中完成,就会抛出IllegalMonitorStateException异常

程序运行到29行时,由于空指针异常,导致lock未上锁(30行的上锁未执行,此时锁的状态是0),最后执行finally代码块中的释放锁,导致报错。
注:未上锁的情况下,直接释放锁会触发``IllegalMonitorStateException``异常


解决方案:

修改:在finally代码块释放锁之前,确保成功上锁了。即上锁的代码需要放在可能有异常的代码之前。最简单粗暴的方法就是在方法第一行加锁。这样保证了释放锁的时候,锁肯定了上锁状态(锁的状态为1)

修改代码:将上锁逻辑提前

private static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) {
        try {
            String name = null;
            lock.lock(); // 在可能抛其他异常前上锁,避免因未上锁状态下释放锁而导致IllegalMonitorStateException异常。上锁后,lock状态是1
            String[] arr = name.split(","); // 1、此处将触发空指针异常。但是已成功上锁
        } catch (Exception e) {
            logger.error("ERROR : ", e); // 2、打印异常
        } finally {
            lock.unlock(); // 3、释放锁。此时lock锁可以正常释放,不会报IllegalMonitorStateException异常
        }
        System.out.println("【 excute successfully 】");
    }

在这里插入图片描述
运行完控制台:程序未报运行时异常,成功执行结束
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值