《锁得住,才能活得久》——一篇讲透 Redisson 分布式锁的技术实录

357 阅读5分钟

——来自一位被死锁坑哭后发誓要掌控全局的程序员的灵魂写作


一、💣💣💣 为啥不用 RedisTemplate 来搞锁?

你是不是也干过这种事儿:

Boolean success = redisTemplate.opsForValue().setIfAbsent("lockKey", "anyVal", 10, TimeUnit.SECONDS);

再加上 delete("lockKey") 释放锁,看上去人畜无害、灵活轻便。
但它有三个致命问题:


❌ 问题 1:线程挂了,锁永远不释放?

忘记加过期时间,锁变成僵尸锁,谁都抢不走,业务直接卡死。


❌ 问题 2:释放锁误删别人的锁!

线程 A 加锁,过期前刚好线程 B 重复拿到锁,
结果线程 A 还在 finally 里执行了 delete("lockKey") ——
恭喜你,B 的锁被误删,相当于别人家刚换门锁,你拿着老钥匙又打开了!


❌ 问题 3:没有重入性、没有阻塞等待、没有续期机制!

你要想支持:

  • 自动续期(像看门狗那样)❌
  • 阻塞等待一会再试 ❌
  • 公平锁 ❌
  • 锁续命 ❌
  • 可重入锁 ❌
  • tryLock 等待+租期 ❌

基本上就是个“山寨锁”,功能少得可怜。


❌ 问题 4:不支持 RedLock / 多节点一致性

你用 RedisTemplate 时,是不具备多 Redis 节点下的锁一致性方案的(比如云 Redis 异地多活、主从切换等),一出故障就“锁飞了”。


✅ 所以 —— 用 Redisson 的理由就呼之欲出了!

Redisson 做到了:

  • 分布式安全性
  • 可重入 / 可中断
  • 看门狗续期机制
  • 公平锁 / 异步锁 / 读写锁等丰富锁模型
  • 天然支持 Spring Boot 与注解式加锁@RedissonLock 插件还有人封装);
  • 源码成熟、功能完备、开箱即用

一切你想要的,Redisson 都有,
一切你不想处理的,Redisson 替你兜底。


好了,我们正式开启 Redisson 世界的奇幻冒险之旅 🧙‍♂️👇


🐕 二、Redisson 的“看门狗”机制:程序员的贴身保镖

Redisson 的锁有个神奇的地方:你只管加锁,逻辑没处理完,它会自动帮你续命。

🔦 默认行为:

  • 使用 lock() 加锁时,Redisson 会启动一个后台线程;
  • 每 10 秒续一次命;
  • 每次把锁的过期时间续到 30 秒;
  • 只要你线程活着,它就一直守着锁。

这就像你不小心把车停在了限时 30 分钟的车位上,看门狗每 10 分钟帮你喂个硬币进去续费……直到你走。

只要逻辑未处理完,每隔10秒,续命30秒,无限重复


🕓 三、我能不能说“不用看门狗”?当然能!

Redisson 不是你丈母娘,它不会一直管着你。

如果你使用如下方式:

lock.lock(5, TimeUnit.SECONDS); // 锁 5 秒,不续期

或者:

lock.tryLock(3, 5, TimeUnit.SECONDS); // 最多等3秒,加锁后锁5秒

你就相当于告诉 Redisson:别续了,我知道自己几斤几两。


🧱 四、lock vs tryLock vs unlock,谁是核心戏骨?

方法特点适合场景
lock()阻塞等待,拿不到锁就等下去一定要拿到锁的业务
lock(time, unit)阻塞,但限定持有时间(关闭看门狗)执行时间可控的业务
tryLock()不等!拿不到锁立刻走高并发快速失败场景
tryLock(wait, lease, unit)等待一段时间,拿到后最多持有 lease 时间推荐 ✅
unlock()主动释放锁(别忘了!不然看门狗续你一脸)finally 里使用

⚠️ 小提醒:只有加锁成功的线程,才能 unlock()。否则你会看到报错:IllegalMonitorStateException,仿佛 Redisson 对你喊:“你谁啊?”


🍱 五、常用方法使用示例

RLock lock = redissonClient.getLock("myLock");

try {
    if (lock.tryLock(3, 10, TimeUnit.SECONDS)) {
        // 拿到锁后执行逻辑
    } else {
        // 没拿到锁,降级处理
    }
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
} finally {
    if (lock.isHeldByCurrentThread()) {
        lock.unlock();
    }
}

🌱 六、Spring Boot 整合 Redisson 步骤(超简明)

1️⃣ 引入依赖

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.24.3</version> <!-- 版本可根据需要调整 -->
</dependency>

2️⃣ 配置 application.yml

#老版本的 redisson-spring-boot-starter(大概 3.13.x 及以前)的写法

redisson:
  config: |
    singleServerConfig:
      address: "redis://localhost:6379"
      password: null
    threads: 4
    nettyThreads: 4


--------------------------根据版本选择其中一个----------------------------------------


#新版本 redisson-spring-boot-starter(3.16.x 之后一直到现在 3.37.x)的写法

spring:
  redis:
    redisson:
      config: |
        singleServerConfig:
          address: "redis://yiqiquhuxi.cn:6379"
          password: "gaga"
        threads: 4
        nettyThreads: 4  
        

3️⃣ 注入使用

@Autowired
private RedissonClient redissonClient;

public void doSomething() {
    RLock lock = redissonClient.getLock("taskLock");
    lock.lock(); // or tryLock(...)
    try {
        // your biz logic
    } finally {
        lock.unlock();
    }
}

🧠 七、还有哪些你没问但必须知道的关键知识点?

✅ 1. 可重入锁(ReentrantLock)

Redisson 的 RLock 是可重入的,同一个线程加锁多次不会被锁死!

lock.lock(); // 第一次
lock.lock(); // 第二次(也能拿到)

✅ 2. 公平锁 vs 非公平锁

  • 默认是非公平锁(谁快谁上)
  • 支持使用 getFairLock(...) 获取公平锁(按排队顺序)

✅ 3. 可中断锁

lock.lockInterruptibly();

可响应 Thread.interrupt() 中断信号,适合线程池控制下的安全退出。

✅ 4. 异步加锁(带 Async 后缀)

支持 tryLockAsync()unlockAsync() 等异步调用方式,适合响应式编程。

✅ 5. 分布式锁的 RedLock?慎用!

RedLock 要在多个 Redis 节点上都加锁才算成功,理论好,但实践中容错差,官方不建议在生产使用(尤其云 Redis 环境)!


🎯 八、结语:做分布式系统的你,要会用这把“云端锁”

程序员的成长,不止是能写 for 循环,还要敢用分布式锁;
Redisson,不是唯一的方案,却是可靠的朋友。

下次你再遇到并发、库存、定时任务、幂等性问题时,别忘了手握 Redisson,心里才稳当。


🐶 九、拓展:看门狗底层逻辑 (懂你就点赞👍🏻)

  • 🐶 加锁时生成 lockId,并绑定线程 ID,谁加的锁谁续命。
  • 🐶 每 10 秒检查 lockId 是否还在,没了说明业务结束(代码执行unlock了),狗退场。
  • 🐶 如果还在,就续 TTL 为 30 秒,直到你主动 unlock。