压测踩坑--redisson释放锁失败

最近在做压测,在日志中看到报了这样的问题。
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。

你可能感兴趣的:(压测踩坑--redisson释放锁失败)