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

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

相关推荐
w***37515 分钟前
SpringBoot【实用篇】- 测试
java·spring boot·后端
9ilk27 分钟前
【C++】 --- 哈希
c++·后端·算法·哈希算法
MC丶科44 分钟前
Spring Boot + Elasticsearch 实现全文搜索功能(商品搜索)!让搜索快如闪电
spring boot·后端·elasticsearch·软考高级·软考架构师
9***P3341 小时前
Rust在网络中的Rocket
开发语言·后端·rust
Wzx1980122 小时前
go聊天室
开发语言·后端·golang
chenyuhao20242 小时前
MySQL索引特性
开发语言·数据库·c++·后端·mysql
oouy2 小时前
《Java泛型:给你的代码装上“快递分拣系统”,再也不会拆出一双鞋!》
后端
Python私教2 小时前
别再瞎折腾 LangChain 了:从 0 到 1 搭建 RAG 知识库的架构决策实录
后端
微学AI2 小时前
openGauss在AI时代的向量数据库应用实践与技术演进深度解析
后端
前端伪大叔2 小时前
第29篇:99% 的量化新手死在挂单上:Freqtrade 隐藏技能揭秘
后端·python·github