Redisson

基于Redisson的分布式锁

该方法实现了一个基于Redisson的分布式锁获取逻辑,支持可中断和不可中断的锁等待。功能如下:

  1. 尝试获取锁 :通过tryAcquire尝试加锁,失败则返回剩余生存时间(TTL)。
  2. 订阅锁释放事件:若未获取锁,则订阅锁释放通知,进入等待。
  3. 循环重试获取锁:在锁被持有期间持续重试,根据TTL等待或阻塞直到锁释放。

以下是对这段代码的逐行详细注释

java 复制代码
private void lock(long leaseTime, TimeUnit unit, boolean interruptibly) throws InterruptedException {
    // 获取当前线程的 ID,用于标识锁的持有者
    long threadId = Thread.currentThread().getId();

    // 尝试获取锁,并返回锁的剩余生存时间(TTL)。
    // 如果返回 null,表示成功获取锁;否则需要进入等待逻辑。
    Long ttl = this.tryAcquire(leaseTime, unit, threadId);

    // 如果 ttl 不为 null,说明锁已被其他线程持有,需要订阅锁释放事件并等待
    if (ttl != null) {
        // 订阅锁释放通知,返回一个 Future 对象,用于监听锁是否被释放
        RFuture<RedissonLockEntry> future = this.subscribe(threadId);

        // 根据 interruptibly 参数决定使用可中断还是不可中断的同步方式
        if (interruptibly) {
            // 可中断的方式同步订阅,允许在等待过程中响应中断
            this.commandExecutor.syncSubscriptionInterrupted(future);
        } else {
            // 不可中断的方式同步订阅
            this.commandExecutor.syncSubscription(future);
        }

        try {
            // 进入自旋循环,持续尝试获取锁直到成功或超时
            while(true) {
                // 再次尝试获取锁,判断是否已释放
                ttl = this.tryAcquire(leaseTime, unit, threadId);

                // 如果 ttl 为 null,说明成功获取锁,退出循环
                if (ttl == null) {
                    return;
                }

                // 如果 TTL 大于等于 0,说明锁还有剩余时间,等待指定的时间
                if (ttl >= 0L) {
                    try {
                        // 使用信号量(latch)等待指定时间,尝试获取锁
                        ((RedissonLockEntry)future.getNow()).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
                    } catch (InterruptedException var13) {
                        // 捕获中断异常,如果 interruptibly 为 true,则重新抛出
                        InterruptedException e = var13;
                        if (interruptibly) {
                            throw e;
                        }

                        // 如果 interruptibly 为 false,则继续等待
                        ((RedissonLockEntry)future.getNow()).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
                    }
                } 
                // 如果 TTL 小于 0,说明没有设置超时时间,直接阻塞等待锁释放
                else if (interruptibly) {
                    // 可中断方式阻塞等待
                    ((RedissonLockEntry)future.getNow()).getLatch().acquire();
                } else {
                    // 不可中断方式阻塞等待
                    ((RedissonLockEntry)future.getNow()).getLatch().acquireUninterruptibly();
                }
            }
        } finally {
            // 取消订阅,释放资源,避免内存泄漏
            this.unsubscribe(future, threadId);
        }
    }
}

✅ 总结

  • tryAcquire(...):尝试获取锁,失败则返回锁的剩余生存时间(TTL)。
  • subscribe(...):订阅锁释放事件,以便在锁释放时收到通知。
  • syncSubscription(...) / syncSubscriptionInterrupted(...):根据是否支持中断选择不同的订阅策略。
  • 自旋 + latch 等待机制:通过不断重试和信号量控制,确保线程在锁释放后能及时获取。
  • unsubscribe(...):确保资源释放,避免内存泄漏。

🔧 推荐优化建议(可选)

如果你希望提高系统的健壮性和灵活性,可以考虑使用 tryLock(...) 方法并设置合理的超时时间,以避免长时间阻塞。例如:

java 复制代码
if (lock.tryLock(5, TimeUnit.SECONDS)) {
    try {
        // 执行关键业务逻辑
    } finally {
        lock.unlock();
    }
} else {
    log.warn("未能获取到锁,跳过本次执行");
}

这种方式更适合对响应时间有要求的场景。

相关推荐
方圆想当图灵1 分钟前
关于 Nacos 在 war 包部署应用关闭部分资源未释放的原因分析
后端
Lemon程序馆11 分钟前
今天聊聊 Mysql 的那些“锁”事!
后端·mysql
龙卷风040514 分钟前
使用本地IDEA连接服务器远程构建部署Docker服务
后端·docker
vv安的浅唱18 分钟前
Golang基础笔记七之指针,值类型和引用类型
后端·go
陪我一起学编程29 分钟前
MySQL创建普通用户并为其分配相关权限的操作步骤
开发语言·数据库·后端·mysql·oracle
Heo1 小时前
调用通义千问大模型实现流式对话
前端·javascript·后端
Java水解2 小时前
RabbitMQ用法的6种核心模式全面解析
后端·rabbitmq
用户4099322502122 小时前
FastAPI的查询白名单和安全沙箱机制如何确保你的API坚不可摧?
前端·后端·github