赞
踩
redission解锁异常:
Redission中的"attempt to unlock lock, not locked by current thread by node id"
lock.lock(leaseTime, Unit)不设置参数,即lock.lock(),才能触发启动Redission的“看门狗”机制(守护线程)。
否则若设置了参数,则到期就释放掉锁。
因为:
Redisson的Watch Dog看门狗机制只会在未显式设置最大持锁时间才会生效。换言之,一旦调用lock方法时指定了leaseTime参数值,则该锁到期后即会自动释放。Redisson的Watch Dog看门狗不会对该锁进行自动续期
补充说明:
- 当我们未显式设置Config类的lockWatchdogTimeout字段值时,使用默认的30秒。此时如果加锁时未显式设置最大持锁时间,即Watch Dog看门狗机制会生效的场景中。该锁实际上一开始也会设置一个默认的最大持锁时间,即30秒。然后看门狗每隔10秒(30秒 * 1/3 = 10秒)会将该锁的最大持锁时间再次设置为30秒,以达到自动续期的目的。这样只要持锁线程的业务还未执行完,则该锁就一直有效、不会被自动释放。当然一旦持锁的服务实例发生宕机后,看门狗的定时任务自然也无法续期。这样锁到期后也就释放掉了,避免了死锁的发生
1. 使用lock.tryLock()替换lock.lock(),不停的尝试解锁。
2. 同时finally中添加代码`if (lock.isLocked && lock.isHeldByCurrentThread())`,先判断锁是否存在、若存在则判断持有锁的是否是当前线程,则才能执行解锁操作。
这样就避免了:
①当前线程业务执行完毕(即锁不存在了,锁存在则看门狗会定时帮着续期)且锁过期释放了(锁已经不存在了),
然后代码又走到了finally中,执行unlock(),导致执行二次释放锁。导致报错(attempt unlock ..企图解锁)。(锁已经不存在了,还解什么锁!当然报错喽~)
②别的线程tryLock()没获取到锁之后,
然后代码也是会走到了finally中,执行unlock(),导致的报错。
- RLock lock = redissonClient.getLock(SHUI_WEN_ST_PPTN_R_QUEUE);//参数是给锁起个名字name,不要重复
- try {
- // 尝试抢获取锁,等待10秒(没抢到就算了,不循环抢),锁自动释放时间expire_time为30秒
- boolean isGetLocked = lock.tryLock(10, 30, TimeUnit.SECONDS);//也可以只传两个参数(等待时间和单位,默认expire_time为30秒)
- if (isGetLocked) {
- // 执行需要保护的“业务”代码
- ...
- ...
- } else {
- // 未获得锁,处理锁定失败的情况
- log.info("抢锁失败");
- }
- } catch (InterruptedException e) {
- // 处理中断异常
- log.error("系统异常",e);
- Thread.currentThread().interrupt();
- } finally {
- // 解锁前检查当前线程是否持有该锁
- if (lock.isLocked && lock.isHeldByCurrentThread()) {
- lock.unlock();
- log.info("解锁成功");
- }
- }
对如下文章作者表示感谢!参考自:
分布式锁(三):基于Redisson的分布式锁实践 - 知乎 (zhihu.com)
Redission 解锁异常:attempt to unlock lock, not locked by current thread by node id_ℳ₯㎕ddzོꦿ࿐的博客-CSDN博客
redission分布式锁释放异常问题 - 简书 (jianshu.com)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。