引言
在分布式架构中,多台服务器共享同一资源时,传统的 JVM 锁已无法保障数据一致性,分布式锁由此成为关键。Redisson 基于 Redis 实现的分布式锁,不仅支持可重入、自动续期,还通过发布订阅机制高效处理锁竞争。本文从加锁、锁续命、锁释放三个环节,深入解析 Redisson 的核心设计,包括 Lua 脚本保证原子性、Watch Dog 看门狗的定时续期机制,以及如何灵活控制锁的失效策略。
Redisson分布式锁实现
分布式锁是为了解决分布式架构中多台服务器共享资源的并发问题,单体时代可以使用JVM锁解决并发问题,但分布式架构中,同时存在多台服务器执行同样的逻辑,也就是在多套JVM环境下执行同样的逻辑,此时JVM锁无法生效,所以需要分布式锁。
加锁过程

还未加锁
-
先判断是否存在key为KEYS[1]的键值对(==0表示不存在),如果不存在表示未加锁。
-
通过hset(Hash结构)设置<锁名称, <UUID + 线程ID, 1>>,KEYS[1] = 锁名称,ARGV[2] = UUID + 线程ID。
-
通过pexpire设置key的过期时间,默认30s。
已经加锁
-
通过hexists(Hash结构)判读前线程是否加锁成功,如果当前线程加锁成功走2。
-
给当前线程的value+1。
-
在次通过pexpire设置key的过期时间,默认30s。

加锁失败
-
通过ttl返回剩余过期时间,方便后续线程重试去竞争锁,如果加锁成功则返回null。
-
加锁失败后会订阅频道(redisson_lock__channel + lockName)返回一个Future用于获得锁释放通知,并通过Semaphore.tryAcquire(ttl, TimeUnit.MILLISECONDS)在ttl时间内尝试获取一个信号量许可,获取到信号量许可后再次进行锁竞争,直至成功。

锁续命过程
使用锁续命而不是不限时的锁,是为了防止用户线程崩溃,导致锁一直未释放。所以每隔一段时间进行锁的续命,而不是设置永久锁,这样即便用户线程崩溃,也只是30s,无法访问。
-
锁续命需要判断用户是否设置过期时间,如果设置了过期时间,不会进行锁续命。
-
通过定时任务每30/3秒,找到当前线程对应的锁,如果存在重新设置过期时间为30秒。


锁释放过程
-
判断线程id(小key)是否存在,如果不存在,则返回null;如果存在,则可重入次数-1。
-
再判断可重入次数是否 > 0,如果 > 0,则不能释放锁,并重新设置锁过期时间。
-
如果 <= 0,则删除redis的大key,往(redisson_lock__channel + lockName)频道发送message,发送UNLOCK_MESSAGE。

Watch Dog(看门狗)
看门狗如何实现锁续期的?
第一次进入的时候,这里放进去的就是一个全新的ExpirationEntry类,并进行续约操作。续约操作其实就是创建一个延迟任务,默认每10s执行一次,延迟任务由HashedWheelTimer实现,核心是时间轮算法。

如何修改看门狗续期时间?
配置lockWatchdogTimeout参数,可以调整看门狗续期频率和续期时间,默认lockWatchdogTimeout/3秒自动需求。
Config config = new Config();
config.setLockWatchdogTimeout(60000); // 设置为 60 秒
如何设置看门狗不会续期?
指定leaseTime参数,这表示锁的有效期。在这个时间之后,如果没有主动释放,锁将自动失效并释放资源。
RLocklock= redissonClient.getLock("myLock");
// 试图加锁,锁的过期时间设置为10秒钟
lock.lock(10, TimeUnit.SECONDS);
情况下,Redisson的看门狗机制会停止续期?
-
第一种情况:手工调用停止续期方法即cancelExpirationRenewal(),看门狗机制会停止续期。
-
第二种情况:调用unlock()释放分布式锁后,看门狗机制也会停止续期。
-
第三种情况:如果尝试续期的过程中,当前线程被中断,看门狗机制也会停止续期。
-
第四种情况:应用程序宕机或者进程被kill掉,看门狗机制也会停止续期。
感谢您的阅读!如果文章中有任何问题或不足之处,欢迎及时指出,您的反馈将帮助我不断改进与完善。期待与您共同探讨技术,共同进步!