前言
在用redisson 下来锁做接口防抖(重复提交)的时候,发现报了“attempt to unlock lock, not locked by current thread”这个错,这里简单分析一下原因,以及给出解决方案。
问题伪代码
RLock lock = redissonClient.getLock("业务编号");
log.info("图文问诊患者去支付入参:{}", JsonUtil.toJson(param));
try {
if (lock.tryLock(0, 30, TimeUnit.SECONDS)) {
// 业务流程
} else {
log.info("userCode:{},patientCode:{},doctorCode:{},请勿频繁发起付款!", param.getUserCode(), param.getPatientCode(), param.getDoctorCode());
throw new BizException("请不要频繁发起付款");
}
} catch (BizException e) {
log.error("图文问诊去支付异常:{}", e.getMessage());
throw e;
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
代码功能简单说明:
做支付的时候,接口被调用了两次,第一次还没有执行完,点了第二次,此时第二次获取不到锁,理想情况下要抛出异常“请不要频繁发起付款”,但是报了错 “attempt to unlock lock, not locked by current thread”,这是因为第二次进来没有获取到锁,直接进去到了finally,执行了 lock.unlock(),第二个请求尝试解锁一个没有被当前线程锁定的锁
解决办法
RLock lock = redissonClient.getLock("业务编号");
log.info("图文问诊患者去支付入参:{}", JsonUtil.toJson(param));
try {
if (lock.tryLock(0, 30, TimeUnit.SECONDS)) {
// 业务流程
} else {
log.info("userCode:{},patientCode:{},doctorCode:{},请勿频繁发起付款!", param.getUserCode(), param.getPatientCode(), param.getDoctorCode());
throw new BizException("请不要频繁发起付款");
}
} catch (BizException e) {
log.error("图文问诊去支付异常:{}", e.getMessage());
throw e;
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
// 解锁前检查当前线程是否持有该锁
if (lock != null && lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
只需要在finally 里面判定是否是当前线程的锁,如果是在进行解锁就好了