背景
最近项目中redis加锁失败,出现了 attempt to unlock lock, not locked by current thread by node id: f4b01cb0-f7c6-4ce7-b6a1-6c09ca56c597 thread-id
异常,导致 tryLock
里面的方法没有执行,引起了事故。
分析
以下是伪代码
RedissonClient redission = redissonComponent.getRedisson();
String key = RedisConstant.getKey("testLock");
RLock lock = redission.getLock(key);
try {
//30秒内,只能有一个线程触发
if (lock.tryLock(30, TimeUnit.SECONDS)) {
//我是执行代码
}
} catch (Exception e) {
logger.error("异常", e);
} finally {
lock.unlock();
}
这个代码已经在线上执行了很久了,突然就出现问题了,首先想到的是是不是redis出现问题了,看了下网络和状态都是正常的。然后看lock.unlock的方法,异常就是从这里抛出来的:
是因为等了30秒,没有获取到锁,所以抛出来,这里去解锁的时候需要判断当前线程是否有锁。
if(lock.isLocked()){
lock.unlock();
}
这样就不会抛异常了,但是还是没有解决加锁失败的问题。继续查看redisson的源码,发现如果不设置leaseTime的话,那么锁的key是不会过期的,如代码:
在查看redis里面的key,结果如下:
ip:6389[1]> hgetall testLock
adc001e3-89b4-4e40-bc64-e45f7f027d42:293
1
ip:6389[1]> pttl testLock
24204
ip:6389[1]> pttl testLock
21096
ip:6389[1]> pttl testLock
29175
ip:6389[1]> pttl testLock
20325
ip:6389[1]> pttl testLock
28518
发现testLock的过期时间一直在刷新,这就导致其他线程加锁不成功。
解决
- 使用的时候加个leaseTime;
- 解锁的时候判断下锁是否还在;
RedissonClient redission = redissonComponent.getRedisson();
String key = RedisConstant.getKey("testLock");
RLock lock = redission.getLock(key);
try {
//30秒内,只能有一个线程触发
if (lock.tryLock(30,30, TimeUnit.SECONDS)) {
//我是执行代码
}
} catch (Exception e) {
logger.error("异常", e);
} finally {
if(lock.isLocked()){
lock.unlock();
}
}
本文为博主原创文章,未经博主允许不得转载。
更多内容请访问:IT源点
注意:本文归作者所有,未经作者允许,不得转载