watchdog解锁失败,会不会导致一直续期下去?
1 个回答
世界上没有快乐的地方,只有快乐的人。黛林在 Redisson 中,即使解锁失败,`watchdog` 也不会一直续期,因为 Redisson 会在解锁过程中保证停止本地续期任务,以避免锁的无效续期。 ### 解锁过程分析 Redisson 的解锁通过 `unlockAsync` 方法实现,其中包含两个关键步骤: 1. **执行解锁**:即实际发送 Redis 解锁命令。 2. **停止续期任务**:不论解锁成功或失败,Redisson 都会调用 `cancelExpirationRenewal` 来取消续期任务。 Redisson 使用 `CompletionStage` 和 `handle` 方法来处理解锁的后续操作,确保即使解锁失败或抛出异常,续期任务也会停止: ```java CompletionStage<Void> f = future.handle((opStatus, e) -> { cancelExpirationRenewal(threadId); if (e != null) { if (e instanceof CompletionException) { throw (CompletionException) e; } throw new CompletionException(e); } if (opStatus == null) { IllegalMonitorStateException cause = new IllegalMonitorStateException("attempt to unlock lock, not locked by current thread by node id: " + id + " thread-id: " + threadId); throw new CompletionException(cause); } return null; }); ``` 在 `handle` 中,`cancelExpirationRenewal` 方法会在任何情况下执行,确保续期任务停止。 ### `cancelExpirationRenewal` 逻辑 `cancelExpirationRenewal` 方法从 `EXPIRATION_RENEWAL_MAP` 中移除当前线程的续期任务,一旦任务不在 `EXPIRATION_RENEWAL_MAP` 中,该锁将不会继续续期: ```java protected void cancelExpirationRenewal(Long threadId) { ExpirationEntry task = EXPIRATION_RENEWAL_MAP.get(getEntryName()); if (task == null) { return; } if (threadId != null) { task.removeThreadId(threadId); } if (threadId == null || task.hasNoThreads()) { Timeout timeout = task.getTimeout(); if (timeout != null) { timeout.cancel(); } EXPIRATION_RENEWAL_MAP.remove(getEntryName()); } } ``` 该方法通过检查 `EXPIRATION_RENEWAL_MAP` 并移除对应线程的任务来防止续期,确保解锁失败不会导致持续续期。 ### 续期的依赖 续期机制依赖 `EXPIRATION_RENEWAL_MAP`,当某个线程不在此 Map 中时,不会再被续期。因此,Redisson 保证解锁失败不会导致无效的续期任务,除非移除 `EXPIRATION_RENEWAL_MAP` 失败,而这是极少发生的。 ### 总结 即便解锁失败或发生异常,Redisson 确保续期任务被取消,不会继续续期,从而防止锁在解锁失败后仍保持续期状态。发布于 2024-10-26 12:29 •IP属地 宁夏举报评论收藏
公众号进入网站体验更佳

