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("未能获取到锁,跳过本次执行");
}

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

相关推荐
东阳马生架构3 小时前
生成订单链路中的技术问题说明文档
后端
程序员码歌6 小时前
【零代码AI编程实战】AI灯塔导航-总结篇
android·前端·后端
java坤坤6 小时前
GoLand 项目从 0 到 1:第八天 ——GORM 命名策略陷阱与 Go 项目启动慢问题攻坚
开发语言·后端·golang
元清加油6 小时前
【Golang】:函数和包
服务器·开发语言·网络·后端·网络协议·golang
bobz9657 小时前
GPT-4.1 对比 GPT-4o
后端
Java小白程序员7 小时前
Spring Framework :IoC 容器的原理与实践
java·后端·spring
小小愿望8 小时前
前端无法获取响应头(如 Content-Disposition)的原因与解决方案
前端·后端
追逐时光者9 小时前
C#/.NET/.NET Core技术前沿周刊 | 第 50 期(2025年8.11-8.17)
后端·.net
杨DaB9 小时前
【SpringBoot】Swagger 接口工具
java·spring boot·后端·restful·swagger
why技术9 小时前
也是震惊到我了!家里有密码锁的注意了,这真不是 BUG,是 feature。
后端·面试