🚀 Redisson 分布式锁源码解析:从加锁到解锁的完整流程

适用版本:Redisson 3.23.5+

核心组件:RedissonLock(可重入锁实现)

涉及模块:Lua 脚本、Redis 发布订阅、内部续期机制(看门狗)


📌 一、Redisson 分布式锁实现简介

Redisson 基于 Redis 实现了多种分布式锁的高级封装,其中 RedissonLock 实现了类似 ReentrantLock 的可重入锁特性。它利用 Redis 的原子操作和发布订阅机制,配合 Lua 脚本、异步任务和线程 ID 维护锁状态。


📍 二、加锁流程源码解析

🔧 外部入口

java 复制代码
RLock lock = redissonClient.getLock("myLock");
lock.tryLock(10, 30, TimeUnit.SECONDS); // 等待最多10秒,成功后30秒自动释放

会进入以下同步方法:

java 复制代码
public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException

🧩 Step 1:尝试加锁 tryAcquire(...)

java 复制代码
Long ttl = tryAcquire(waitTime, leaseTime, unit, threadId);

内部调用的是 Lua 脚本,核心逻辑:

lua 复制代码
if lock not exists:
    hset(lockName, threadId, 1)
    pexpire(lockName, leaseTime)
else if same thread:
    hincrby(lockName, threadId, 1)
    pexpire(lockName, leaseTime)
else:
    return TTL (锁被占用)

返回值:

  • null:加锁成功
  • ttl:加锁失败,返回锁剩余时间

🧩 Step 2:加锁失败 → 订阅发布频道

java 复制代码
CompletableFuture<RedissonLockEntry> subscribeFuture = subscribe(threadId);

订阅的是该锁的发布频道:

java 复制代码
String getChannelName() = prefix + ":{" + lockName + "}:channel"

底层通过 PubSubConnectionEntry 注册订阅,封装为 RedissonLockEntry,包含 CountDownLatch


🧩 Step 3:循环等待并重试加锁

java 复制代码
while (true) {
    Long ttl = tryAcquire(...)
    if (ttl == null) return true;

    latch.tryAcquire(ttl or remainTime)
}

每次被唤醒后再次尝试加锁,直到:

  • 成功获取锁
  • 超时返回 false
  • 异常终止

📍 三、解锁流程源码解析

🔧 unlock() → unlockInnerAsync(...)

java 复制代码
public void unlock() {
    get(unlockInnerAsync(threadId));
}

核心解锁逻辑为:

java 复制代码
protected RFuture<Boolean> unlockInnerAsync(...) {
    return evalWrite(..., Lua脚本, keys, args);
}

🧩 Lua 脚本执行释放逻辑

lua 复制代码
if hexists(lock, threadId) == 0:
    return nil

counter = hincrby(lock, threadId, -1)
if counter > 0:
    pexpire(lock, leaseTime)
else:
    del(lock)
    publish(channel, unlockMessage) -- 唤醒其他订阅者

✅ 只有当线程重入次数减到 0 时,才真正释放锁并发布消息


🧩 发布消息通知其他等待线程

java 复制代码
redis.call(ARGV[4], KEYS[2], ARGV[1])

即:

redis 复制代码
PUBLISH <channel> <unlockMessage>

LockPubSub 监听该频道,唤醒之前 subscribe() 创建的 RedissonLockEntry.getLatch()


📍 四、看门狗机制(Watchdog)

若调用如下代码:

java 复制代码
lock.lock(); // 不指定 leaseTime

Redisson 会自动启用看门狗机制,每隔 10s 续约一次(默认租期 30s):

java 复制代码
scheduleExpirationRenewal(threadId)

核心续约命令:

java 复制代码
pexpire(lockKey, 30000)

续期任务在:

  • 锁未释放前持续运行
  • 线程释放锁后自动取消

✅ 五、源码流程图(文字版)

scss 复制代码
┌────────────────────────┐
│       tryLock()        │
└────────────┬───────────┘
             ↓
┌────────────────────────┐
│   tryAcquire (Lua脚本) │
│  - 加锁成功 → 返回null │
│  - 失败 → 返回TTL时间  │
└────────────┬───────────┘
             ↓
┌────────────────────────────┐
│   subscribe + latch等待    │
│   订阅释放频道,等待通知   │
└────────────┬───────────────┘
             ↓
┌────────────────────────┐
│   收到消息重新tryAcquire │
│   成功 → true 失败→重试  │
└────────────┬───────────┘
             ↓
┌────────────────────────────┐
│           unlock()         │
│   - hincrby重入次数减1     │
│   - 发布unlock通知         │
└────────────────────────────┘

📍 六、小结与建议

特性 描述
加锁脚本 Lua 保证原子性,兼容可重入逻辑
解锁通知 Redis 发布订阅频道通知其他线程唤醒尝试加锁
看门狗续期 解决业务执行过长导致锁过期问题(自动延期)
支持公平锁 Redisson 另有 RedissonFairLock 实现公平队列(推荐高并发下使用)

📚 七、推荐阅读源码类

  • RedissonLock:核心加锁解锁逻辑
  • LockPubSub:发布订阅机制
  • CommandAsyncExecutor:命令异步封装
  • RenewalTask:看门狗定时器逻辑
  • tryAcquireAsync0():真正的加锁内部实现
  • evalWrite(...):执行 Lua 脚本的统一方法
相关推荐
计算机毕设匠心工作室10 小时前
【python大数据毕设实战】青少年抑郁症风险数据分析可视化系统、Hadoop、计算机毕业设计、包括数据爬取、数据分析、数据可视化、机器学习
后端·python
计算机毕设小月哥10 小时前
【Hadoop+Spark+python毕设】智能制造生产效能分析与可视化系统、计算机毕业设计、包括数据爬取、Spark、数据分析、数据可视化、Hadoop
后端·python·mysql
四问四不知10 小时前
Rust语言进阶(结构体)
开发语言·后端·rust
WZTTMoon11 小时前
Spring Boot 启动全解析:4 大关键动作 + 底层逻辑
java·spring boot·后端
小二·11 小时前
Spring框架入门:深入理解Spring DI的注入方式
java·后端·spring
毕设源码-钟学长12 小时前
【开题答辩全过程】以 基于springboot和协同过滤算法的线上点餐系统为例,包含答辩的问题和答案
java·spring boot·后端
计算机毕设小月哥12 小时前
【Hadoop+Spark+python毕设】中风患者数据可视化分析系统、计算机毕业设计、包括数据爬取、Spark、数据分析、数据可视化、Hadoop
后端·python·mysql
q***441512 小时前
Spring Security 新版本配置
java·后端·spring
计算机毕设匠心工作室12 小时前
【python大数据毕设实战】强迫症特征与影响因素数据分析系统、Hadoop、计算机毕业设计、包括数据爬取、数据分析、数据可视化、机器学习、实战教学
后端·python·mysql
o***741712 小时前
Springboot中SLF4J详解
java·spring boot·后端