Redisson解锁失败,watchdog会不会一直续期下去?

不用担心这个问题。在解锁过程中,无论解锁失败还是抛出异常,都会停止本地的续期任务,防止后续自动续期。具体实现逻辑如下:

java 复制代码
@Override
public void unlock() {
    try {
        get(unlockAsync(Thread.currentThread().getId()));
    } catch (RedisException e) {
        if (e.getCause() instanceof IllegalMonitorStateException) {
            throw (IllegalMonitorStateException) e.getCause();
        } else {
            throw e;
        }
    }
}

这段代码是Redisson解锁方法的入口,会调用unlockAsync方法并传入当前线程ID:

java 复制代码
@Override
public RFuture<Void> unlockAsync(long threadId) {
    return getServiceManager().execute(() -> unlockAsync0(threadId));
}

private RFuture<Void> unlockAsync0(long threadId) {
    CompletionStage<Boolean> future = unlockInnerAsync(threadId);
    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;
    });

    return new CompletableFutureWrapper<>(f);
}

核心逻辑包含两个关键步骤:

  1. 执行解锁操作:unlockInnerAsync(threadId)
  2. 处理解锁结果:通过CompletionStagehandle方法执行后续操作

CompletionStage是Java 8引入的异步编程接口,它的handle方法能够处理操作的成功或失败状态。方法签名如下:

java 复制代码
<T> CompletionStage<T> handle(BiFunction<? super T, Throwable, ? extends T> fn);

无论unlockInnerAsync过程中是否成功或出现异常,后续代码都会执行。其中关键部分是:

java 复制代码
cancelExpirationRenewal(threadId);

这个方法的实现:

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中移除当前线程。由于自动续期依赖于该Map,移除后就不会再续期了。除非从本地Map中移除key的操作也失败,但这种概率极低。

相关推荐
njidf1 分钟前
Python日志记录(Logging)最佳实践
jvm·数据库·python
twc8291 分钟前
大模型生成 QA Pairs 提升 RAG 应用测试效率的实践
服务器·数据库·人工智能·windows·rag·大模型测试
@我漫长的孤独流浪1 分钟前
Python编程核心知识点速览
开发语言·数据库·python
2401_851272993 分钟前
实战:用Python分析某电商销售数据
jvm·数据库·python
lay_liu5 分钟前
Linux安装redis
linux·运维·redis
枕布响丸辣10 分钟前
MySQL 从入门到精通:完整操作手册与实战指南
数据库·mysql
电商API&Tina21 分钟前
【电商API接口】开发者一站式电商API接入说明
大数据·数据库·人工智能·云计算·json
2401_8579182923 分钟前
用Python和Twilio构建短信通知系统
jvm·数据库·python
樹JUMP28 分钟前
使用Docker容器化你的Python应用
jvm·数据库·python
原来是猿1 小时前
MySQL【用户管理】
数据库·mysql