最近在做压测,在日志中看到报了这样的问题。
java.lang.IllegalMonitorStateException: attempt to unlock lock, not locked by current thread by node id: 82baf554-625b-4c19-9559-f37dc85f499e thread-id: 692
之前写的分布式锁的实现被以为同事替换成了redisson了。没注意看,就按照他们写的照搬了。结果在压测的时候,就发现了如下问题。一看日志第一反应想的还以为是多个线程跑进来了,然后解锁不是自己的锁。然后屁颠屁颠去看代码。
//大概代码如下:
public String nextNo(String prefix, Integer numberLength) {
RLock lock = redisson.getLock(serviceName + LOCK_KEY_PREFIX + prefix);
try {
if (lock.tryLock(5, TimeUnit.SECONDS)) {
//业务代码,主要就是setnx;
return prefix + formatDate + String.format("%0" + numberLength + "d", num);
} else {
//业务代码 ...
throw SystemBaseExceptionEnum.COMMON_ERROR.getException("生成编号失败!");
}
} catch (BaseException baseException) {
throw baseException;
} catch (Exception e) {
log.error("redis lock an error", e);
throw SystemBaseExceptionEnum.COMMON_ERROR.getException("生成编号失败!");
} finally {
lock.unlock();
}
}
看了代码发现不对劲,这个方法不可能跑进来多个线程呀。一分析才发觉是有的线程超过了5s的等待时间,然后放弃加锁了。放弃加锁后,执行完else中的业务代码。最后调用finally的unlock方法。问题来了,你都没加到锁,解锁个铁锤?
解决方法,finally的代码替换成这样就好了。
finally {
if (lock.isLocked() && lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
所以以后还是不能直接cv别人的code。
网友评论