[Java]Redisson的分布式锁及看门狗机制

本文介绍了在SpringBoot应用中基于Redis+Redisson的分布式锁的基本使用,以及Redisson分布式锁的看门狗机制。

1 添加相关Maven依赖

xml 复制代码
<!-- redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- redis连接池需引入commons-pool2 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

<!-- redisson -->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.18.0</version>
</dependency>

本文的SpringBoot版本为2.7.18,对应最新的redisson版本为3.18.0。

redisson和SpringBoot版本的对应关系可参考文章:redisson版本与springboot版本依赖关系

2 Redisson分布式锁的基本使用

lock():

java 复制代码
@Service
public class TicketService {
    @Resource
    private RedissonClient redissonClient;
    
    private void createTicket() {
        // 获取锁,"lock:createTicket"为锁住的资源名,用于区分不同锁
        RLock lock = redissonClient.getLock("lock:createTicket");
        lock.lock(); // 阻塞等待加锁
        try {
            // 加锁执行的代码
            doCreateTicket();
        } finally {
            if (lock.isLocked()) {
                lock.unlock(); // 释放锁
            }
        }
    }
}

tryLock():

java 复制代码
// 模拟集群部署时的多实例并发问题
public void runTask() {
    // 加锁实现任务的串行,防止同时执行
    RLock lock = redissonClient.getLock("lock:taskName");
    if (lock.tryLock()) { // 尝试获取锁,获取不到直接结束
        try {
            doRunTask();
        } finally {
            lock.unlock(); // 释放锁
        }
    }
}

3 看门狗机制

此章节包含AI生成的内容

Redisson 的 看门狗机制(Watchdog Mechanism) 是其分布式锁功能中最核心、最强大的特性之一,它解决了传统分布式锁中 "锁过期但业务未执行完" 的经典问题。


✅ 一、问题背景:为什么需要看门狗?

假设你用 Redis 实现了一个简单的分布式锁:

java 复制代码
SET lock_key my_instance NX EX 30
  • 设置一个 30 秒过期的锁。
  • 如果业务逻辑执行时间 超过 30 秒,锁自动过期。
  • 此时另一个实例可以获取锁 → 出现 两个实例同时持有锁 → 锁失效!

问题:锁的过期时间必须预估业务执行时间,保守设置会导致并发降低,设置太短又可能提前释放。


✅ 二、Redisson 看门狗机制(Watchdog)是什么?

Redisson 的看门狗是一个 自动续期机制

当一个线程成功获取锁后,Redisson 会启动一个后台线程(看门狗),每隔一段时间(默认 1/3 锁超时时间)自动给锁 延长过期时间,只要持有锁的线程还在运行。


🔧 工作流程图解

scss 复制代码
线程A获取锁(lock())  
       ↓
Redisson 启动看门狗(后台线程)
       ↓
看门狗每 10 秒检查一次(默认)
       ↓
如果线程A仍持有锁 → 执行 EXPIRE lock_key 30
       ↓
锁的 TTL 重新设置为 30 秒
       ↓
直到线程A调用 unlock() → 看门狗停止,锁被删除

✅ 三、关键参数(默认值)

参数 说明
锁默认超时时间(leaseTime) 30 秒 lock() 不传参时的 TTL
看门狗检查间隔 10 秒 30 * 1/3 ≈ 10
续期命令 EXPIRE lock_key 30 重置 TTL

✅ 四、代码示例

java 复制代码
RedissonClient redisson = Redisson.create(config);
RLock lock = redisson.getLock("my:lock");

// 获取锁(默认 30 秒超时,看门狗自动续期)
lock.lock();

try {
    // 执行业务逻辑(可能耗时 1 分钟)
    Thread.sleep(60_000);
    System.out.println("业务执行完成");
} finally {
    // 释放锁 → 看门狗停止,锁被删除
    lock.unlock();
}

在这个例子中:

  • 即使业务执行了 60 秒,锁也不会提前释放
  • 看门狗会在第 10 秒、20 秒、30 秒、40 秒、50 秒时自动续期。
  • 最终 unlock() 被调用,锁被删除。

✅ 五、看门狗如何避免续期风暴?

Redisson 使用了 单例看门狗 + 懒启动 策略:

  • 多个锁共享同一个看门狗调度器。
  • 每个锁的续期任务独立,但调度是高效的。
  • 只有持有锁的线程才启动续期任务。

✅ 六、什么情况下看门狗不会工作?

场景 说明
❌ 使用 lock(long, TimeUnit) 并指定 leaseTime 大于 0 lock.lock(10, SECONDS) 会禁用看门狗
❌ JVM 宕机或线程崩溃 看门狗线程也停止 → 锁会在 TTL 后自动释放(安全)
❌ Redis 宕机 依赖 Redis 高可用(如哨兵、集群)
❌ 网络分区 持有锁的节点失联 → 锁最终过期(遵循 CP 模型)

✅ 七、总结

特性 说明
🎯 核心价值 实现"只要线程活着,锁就不会过期"
⚙️ 自动续期 每 1/3 TTL 时间自动 EXPIRE
🛡️ 防误删 结合 threadId + UUID 唯一标识锁
💡 无需预估时间 业务执行多久都不怕锁过期
推荐使用 lock() 而不是 tryLock() 或带超时的 lock(timeout)

💬 一句话总结

Redisson 的看门狗就像一个"自动浇水的花盆",只要你这朵"花"还活着(线程运行),它就会定时给你"浇水"(续期),防止你"枯死"(锁过期)。

这是 Redisson 分布式锁 高可用、易用、安全 的关键所在。

A 参考内容

相关推荐
IT_陈寒15 分钟前
React的这个渲染问题连官方文档都没说清楚
前端·人工智能·后端
狼爷1 小时前
吃透 Java Function 接口,搞定 99% 的 Stream 场景
java·函数式编程
葫芦和十三1 小时前
图解 MongoDB 15|journal 与持久化:写入怎么不丢,崩溃怎么恢复
后端·mongodb·面试
葫芦和十三1 小时前
图解 MongoDB 16|压缩:snappy、zstd 和 zlib 的取舍
后端·mongodb·面试
苍何1 小时前
终于找到免费开源TTS模型,克隆声音不要钱,本地电脑也能跑
后端
用户593608741402 小时前
Spring AI 集成 DeepSeek 原生供应商并实现think模式
后端
追逐时光者2 小时前
别再满网找零散工具了,腾讯 QQ 浏览器这个“帮小忙”工具箱真能省时间
前端·后端
心静自然凉8002 小时前
Linux网络核心知识+bonding主备模式配置
后端
爻渡4 小时前
异步编程演进史:从回调到Promise再到Async/Await
后端·程序员
要阿尔卑斯吗5 小时前
企业级 RAG 系统的文件标签管理:三层架构与层级优化实战
后端