如何安全地使用 Lock 的unlock() 而不会抛出异常导致程序终止

如何安全地使用 Lock 的unlock() 而不会抛出异常导致程序终止

背景

我们使用 synchronized 的话,不需要我们手工操作lock() 和 unlock(),但是在使用 juc Lock 的时候就需要注意,不注意这些细节,将为你的程序埋下坑,卖容易发现的坑还好,偏偏有些坑是比较隐蔽的。

正确的 unlock()

如何正确的使用Lock#unlock(),如下

  • 建议别用 Lock lock = new ReentrantLock()这样的代码,直接用实现类 ReentrantLock lock = new ReentrantLock()

  • 建议直接用 try-catch 包住异常,并且不处理任何异常,不打印日志

    public safeUnlock(Lock lock) {
         
    	try {
         
    		lock.unlock();
    	} catch(Exception e) {
         
    	
    	}
    }
    
  • 有 isHeldByCurrentThread的,也可以用

    if (lock.isHeldByCurrentThread()) {
         
    	lock.unlock();
    }
    

    但是并不是什么 Lock 的子类都有 isHeldByCurrentThread()所以还是统一用try-catch,一了百了,又统一代码风格。

    • 比如 ReadLock就没有该方法

示例

1、例子1:ReentrantLock 的关闭

unsafeUnlock的写法是危险的,假如在lock.lock() 的上面写了代码,并且这些代码发生了异常,惨了,没获得锁就进行解锁,会抛出了异常。正确的方式是先判断 isHeldByCurrentThread()

private static void testUnlockReentrantLock() {
   
  ReentrantLock lock = new ReentrantLock();
  try {
   
    int i = 8 / 0;
    lock.lock();
    // do sth
  } finally {
   
    unsafeUnlock(lock);// 有风险
    // safeUnlock(lock);// 正确方法
  }
}

private static void unsafeUnlock(ReentrantLock lock) {
   
  lock.unlock();
}
private static void safeUnlock(ReentrantLock lock) {
   
  if (lock.isHeldByCurrentThread()) {
   
    lock.unlock();
  }
  // 注意: 更安全是先判断 lock != null.不过这个不是今天的主角,就不突出NPE判断了
}

2、例子2:ReentrantLock的tryLock的关闭

可以看到,第二个线程因为tryLock设置了超时时间,实际是不能获得线程的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值