Redis 分布式锁的三层演进:
- 不可重入 Redis 分布式锁
- 可重入的 Redis 分布式锁
- Redisson 的 MultiLock
课程里对这三层的总结非常明确:
不可重入锁依赖 setnx 的互斥性、ex 的超时释放和线程标识校验;可重入锁则通过 hash 结构记录线程标识和重入次数,再配合 watchDog 续期 和 信号量/PubSub 重试等待;但 Redis 主从异步复制仍可能导致锁丢失,所以又引出了 MultiLock,要求在多个独立 Redis 节点上都拿到锁才算成功。
Redis 分布式锁进阶学习文档
1. 这一节在整个秒杀模块里的位置
你现在已经从“单机一人一单”走到了“集群下必须用分布式锁”。
而这张图讲的不是“为什么要锁”,而是:
Redis 分布式锁写出来以后,它本身还会继续升级。
课程目录里也明确把这一段拆成了:
- Redis 分布式锁实现
- 锁误删问题
- 原子性问题
- Redisson
- Redisson 可重入锁原理
- Redisson 锁重试和 WatchDog
- Redisson 的 MultiLock
也就是说,这一节是在带你理解:
自己手写的简易 Redis 锁够不够?
不够的话,Redisson 到底帮你补了什么?
2. 第一层:不可重入 Redis 分布式锁
2.1 它的核心原理
课程里总结得很直接:
- 利用
setnx的互斥性 - 利用
ex避免死锁 - 释放锁时判断线程标识
更早的基础版 Redis 锁思路也是一样的:
- 获取锁:
SET lock thread1 NX EX 10 - 释放锁:删除 key
- 获取时设置超时时间,避免服务宕机后永远不释放
你可以把它翻译成业务话:
NX:别人没加锁,我才能加EX:就算线程挂了,锁也会自动过期- 线程标识:解锁时先确认这把锁是不是自己的
2.2 它解决了什么
它解决的是最基础的分布式互斥问题:
- 多个 JVM 可以看见同一把锁
- 同一时刻只有一个线程能执行临界区代码
- 能防止服务异常后锁永远不释放
2.3 它的缺陷
课件已经直接列出来了:
- 不可重入
- 无法重试
- 锁超时失效
PDF 里也进一步解释了这些问题:
基于 setnx 的锁会有 重入问题、不可重试、超时释放带来的安全隐患,而且主从环境下还会有一致性问题。
3. 什么叫“不可重入”
这个概念你一定要吃透。
3.1 重入是什么意思
“重入”指的是:
同一个线程已经拿到了锁,进入方法 A;
方法 A 里面又调用了方法 B;
方法 B 也想拿同一把锁;
这时如果还能成功,就叫可重入。
Java 里的 synchronized 和 Lock 都是可重入的。课程 PDF 里明确指出:
可重入锁的意义是防止死锁。
3.2 不可重入会有什么问题
假设同一个线程已经持有锁,又去尝试获取同一把锁:
- 如果锁系统只知道“这把锁存在”
- 却不知道“持有者还是我自己”
- 那它就会把自己也拦住
这就容易出现“自己锁自己”的死锁风险。
4. 第二层:可重入的 Redis 分布式锁
4.1 课程给出的原理
这张图里已经写得很清楚:
- 利用 hash 结构
- 记录 线程标识
- 记录 重入次数
- 利用 watchDog 延长锁时间
- 利用 信号量 / PubSub 控制锁重试等待
4.2 为什么用 hash
PDF 里明确说了,Redisson 在分布式锁中采用 hash 结构 来存储锁:
- 大 key 表示“这把锁”
- 小 key 表示“哪个线程持有”
- value 记录“重入次数”
你可以这样理解:
lock:order
└── uuid:threadId -> 2
意思是:
lock:order这把锁存在uuid:threadId这个线程持有它- 当前已经重入了 2 次
4.3 可重入锁的加锁逻辑
课件图示的流程本质是:
- 先判断锁是否存在
- 如果不存在,直接加锁,记录当前线程,计数设为 1
- 如果存在,再判断持有者是不是自己
- 如果是自己,计数加 1
- 如果不是自己,获取失败或等待重试
4.4 可重入锁的解锁逻辑
解锁不是直接删 key,而是:
- 判断当前线程是不是持有者
- 如果不是,不能删
- 如果是,重入次数减 1
- 如果减完还大于 0,说明还没真正释放完,只重置过期时间
- 只有减到 0,才真正删除锁
所以可重入锁的关键不是“多次 set”,而是:
记录同一线程重入了多少次,按次数逐步释放。
5. WatchDog 是干什么的
这是可重入锁进阶里最重要的点之一。
课程里明确说:
Redisson 用 watchDog 来做 超时续约,会每隔一段时间重置锁的过期时间。
5.1 为什么需要它
因为基础版 Redis 锁虽然加了过期时间,能避免死锁,但会带来新问题:
如果业务执行时间比锁 TTL 还长,锁会提前过期。
这时候别的线程可能趁机拿到锁,导致并发安全问题。
PDF 里把这个问题称为“超时释放带来的安全隐患”。
5.2 WatchDog 的作用
WatchDog 就像“自动续费”:
- 线程拿到锁后
- 业务还没做完
- 看门狗就定期把锁的过期时间往后延
PDF 还给了源码级说明:
它会在一定周期内调用续期逻辑,线程还活着就继续续约;线程挂了就不再续约,锁最终自然过期释放。
所以你可以记成一句话:
WatchDog 解决的是“业务没执行完,锁先过期”的问题。
6. 可重试是什么意思
基础版锁通常是“抢一次就结束”,拿不到就直接失败。
但课程里说,可重入 Redis 锁还支持:
- 等待
- 重试
- 收到释放信号后再抢
这就是为什么 Redisson 比手写 setnx 锁更完整:
- 不是单纯 try once
- 而是有等待和唤醒机制
- 更接近 Java
Lock的使用体验
7. 可重入 Redis 分布式锁的缺陷
虽然它已经比手写锁强很多,但课件仍然给出一个关键缺陷:
Redis 宕机会引起锁失效问题。
7.1 为什么会这样
PDF 解释得很清楚:
- 你把锁写到 Redis 主节点
- 主节点还没来得及同步给从节点
- 主节点就挂了
- 哨兵把某个从节点提升为新主
- 但新主里根本没有这把锁的信息
结果就是:
锁丢了。
这不是代码写错,而是 Redis 主从异步复制 的一致性边界问题。
8. 第三层:Redisson 的 MultiLock
8.1 它为什么出现
正是为了补 Redis 主从复制下“锁可能丢失”的问题,课程里才引出了 MultiLock。
8.2 它的原理
课件原话就是:
多个独立的 Redis 节点,必须在所有节点都获取重入锁,才算获取锁成功。
PDF 也明确解释了:
- 不再依赖“一个主从集群里的主节点”
- 而是在多个彼此独立的 Redis 节点上分别加锁
- 只有全部成功,才算最终成功
- 只要有一个节点拿不到,就不算加锁成功
你可以把它理解成:
单点锁 = 一票通过
MultiLock = 全票通过
8.3 它解决了什么
它解决的是:
- 某个 Redis 主节点突然宕机
- 锁尚未同步
- 锁信息丢失
因为 MultiLock 把锁分散写到多个独立节点,只要不是所有节点同时丢锁,就能大幅提高可靠性。
9. MultiLock 的缺点
课件里已经给出结论:
- 运维成本高
- 实现复杂
这很好理解:
- Redis 节点更多
- 加锁要写多次
- 失败回滚更复杂
- 网络开销也更高
所以它不是默认首选,而是更强调 可靠性优先 的锁方案。
10. 这三层你要怎么对比着学
第一层:不可重入 Redis 锁
适合你理解 Redis 锁的最小实现:
set nx ex- 线程标识
- 解锁校验
但是问题多:
- 不可重入
- 不能优雅重试
- TTL 到了可能提前失锁
第二层:可重入 Redis 锁 / Redisson Lock
这是企业里更常用的完整方案:
- hash 记录线程和重入次数
- watchDog 自动续期
- 支持等待和重试
但在 Redis 主从切换时,仍可能锁丢失。
第三层:MultiLock
进一步提升可靠性:
- 多节点全部加锁成功才算成功
- 避免单个 Redis 主从切换导致锁失效
但代价是更重、更复杂。
11. 放到黑马点评项目里怎么理解
你现在要把它和秒杀的一人一单联系起来理解:
- 一开始你是用 JVM 锁解决单机一人一单
- 集群后 JVM 锁失效,改用 Redis 分布式锁
- 手写 Redis 锁能跑,但能力不完整
- 最后课程引导你用 Redisson,把可重入、重试、续期这些能力补全
- 再进一步讲主从一致性问题,引出 MultiLock
所以这不是单独知识点,而是:
秒杀业务逼着锁机制一步步升级。
12. 面试表达
你可以直接按这个思路回答:
Redis 分布式锁最基础的实现是基于
set nx ex,利用nx实现互斥,ex防止死锁,再结合线程标识避免误删别人的锁。但这种方案是不可重入的,也不支持等待重试,而且如果业务执行时间超过锁 TTL,会出现锁提前失效的问题。Redisson 在此基础上实现了可重入锁:用 hash 结构记录线程标识和重入次数,用 watchDog 机制自动续期,用等待和唤醒机制支持锁重试。不过在 Redis 主从架构下,如果主节点写入锁后尚未同步就宕机,锁信息可能丢失。为了解决这个问题,Redisson 还提供了 MultiLock,需要在多个独立 Redis 节点上都获取到锁才算成功,从而提高分布式锁的可靠性。
13. 你现在最该记住的 5 句话
- 基础 Redis 锁靠
set nx ex实现互斥和超时释放。 - 不可重入锁的问题是同一线程再次进锁代码时可能把自己卡死。
- Redisson 用 hash 记录线程标识和重入次数,实现可重入。
- WatchDog 解决的是“业务没执行完,锁先过期”的问题。
- MultiLock 解决的是 Redis 主从切换时锁可能丢失的问题。