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 小时前
Feign调Post接口异常:Incomplete output stream
java·后端·微服务
LeeGe3 小时前
SpringAOP中@within和@annotation以及 @within和@target的区别
后端
一个平平无奇的Java小学生3 小时前
Spring Cloud Alibaba 微服务从入门到生产部署完整指南
后端
一个平平无奇的Java小学生3 小时前
Spring Cloud Alibaba 微服务实战指南
后端
张小洛3 小时前
Spring IOC容器核心阶段解密:★Bean实例化全流程深度剖析★
java·后端·spring·ioc容器·bean实例化
小王子10243 小时前
Django+DRF 实战:从异常捕获到自定义错误信息
后端·django·web开发
hdsoft_huge3 小时前
Spring Boot 高并发框架实现方案:数字城市的奇妙之旅
java·spring boot·后端
00后程序员4 小时前
WebView 无法调用原生分享功能?调试复现与异常排查全过程
后端
struggleupwards4 小时前
go-cache 单机缓存
后端
struggleupwards4 小时前
golang 实现删除切片特定下标元素的方法
后端