1. 概述
Redisson 是基于 Redis 实现的 Java 分布式锁框架,其核心设计目标是原子性、可重入性、锁续期和高效锁竞争处理。通过 Redis 的 Hash 数据结构和 Lua 脚本的原子性操作,Redisson 实现了高性能的分布式锁机制,并解决了传统 setnx
命令的局限性212。
2. 核心实现原理
2.1 加锁流程
Redisson 的加锁通过 Lua 脚本实现原子操作,核心逻辑如下:
-- KEYS[1]: 锁名(如 "myLock")
-- ARGV[1]: 锁超时时间(毫秒)
-- ARGV[2]: 锁标识(UUID:线程ID)
if (redis.call('exists', KEYS[1]) == 0) then
redis.call('hincrby', KEYS[1], ARGV[2], 1); -- 首次加锁,计数器设为1
redis.call('pexpire', KEYS[1], ARGV[1]); -- 设置锁超时时间
return nil;
end;
if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then
redis.call('hincrby', KEYS[1], ARGV[2], 1); -- 可重入:计数器+1
redis.call('pexpire', KEYS[1], ARGV[1]);
return nil;
end;
return redis.call('pttl', KEYS[1]); -- 锁被其他线程持有,返回剩余时间
关键点:
-
可重入性:通过 Hash 结构存储锁标识(
UUID:ThreadID
)和计数器,实现同一线程多次加锁214。 -
原子性:Lua 脚本保证加锁操作的原子性,避免
setnx
+expire
分步操作的风险12。
2.2 解锁流程
解锁同样通过 Lua 脚本实现:
-- KEYS[1]: 锁名,KEYS[2]: 发布订阅的 Channel
-- ARGV[1]: 解锁消息标识,ARGV[2]: 锁超时时间,ARGV[3]: 锁标识
if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then
return nil; -- 锁不属于当前线程,拒绝解锁
end;
local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); -- 计数器-1
if (counter > 0) then
redis.call('pexpire', KEYS[1], ARGV[2]); -- 仍有重入次数,仅续期
return 0;
else
redis.call('del', KEYS[1]); -- 计数器归零,删除锁
redis.call('publish', KEYS[2], ARGV[1]); -- 发布解锁消息
return 1;
end;
关键点:
-
安全释放:校验锁归属,防止误删其他线程的锁10。
-
发布订阅机制:解锁时通过 Redis 的 Pub/Sub 通知等待线程重新竞争锁716。
3. 关键机制源码分析
3.1 看门狗(WatchDog)
作用:在未显式指定锁超时时间时,自动续期锁,避免业务未完成时锁过期。
源码实现:
-
续期任务调度:在
scheduleExpirationRenewal
方法中,通过 Netty 的HashedWheelTimer
创建定时任务,默认每internalLockLeaseTime/3
(10秒)执行一次续期1116。 -
续期 Lua 脚本:
if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then redis.call('pexpire', KEYS[1], ARGV[1]); -- 重置锁超时时间 return 1; end; return 0;
3.2 锁竞争处理
当锁被其他线程持有时,当前线程会执行以下逻辑:
-
订阅解锁消息:通过 Redis 的 Pub/Sub 订阅锁释放事件,避免轮询消耗资源716。
-
自旋尝试加锁:在
tryLock
方法中,结合Semaphore
实现阻塞等待,直到超时或收到解锁通知1112。
4. 核心类与源码解析
4.1 RedissonLock
类
-
关键方法:
-
tryLockInnerAsync
:执行加锁 Lua 脚本214。 -
unlockInnerAsync
:执行解锁 Lua 脚本10。
-
-
锁标识生成:
getLockName(threadId)
生成UUID:ThreadID
,确保全局唯一14。
4.2 锁续期与时间轮
-
时间轮(HashedWheelTimer):Netty 提供的高效定时任务调度器,用于实现锁续期任务的延迟执行16。
-
任务调度逻辑:在
renewExpiration
方法中递归调用,形成链式续期11。
5. 优缺点与适用场景
5.1 优点
-
高可用:支持 Redis 集群模式(需配合 RedLock 算法)12。
-
高性能:基于非阻塞的异步通信(Netty)和高效的锁竞争处理916。
-
功能丰富:支持可重入锁、公平锁、联锁等多种锁类型12。
5.2 局限性
-
集群模式风险:Redis 主从异步复制可能导致锁丢失(需 RedLock 解决)12。
-
依赖 Redis:Redis 宕机可能导致锁服务不可用。
Redisson 通过 Lua 脚本、Hash 数据结构、看门狗机制和发布订阅模型,实现了高性能、高可靠的分布式锁。其源码设计充分考虑了原子性、可重入性和锁续期问题,是分布式系统中锁管理的优选方案。对于高并发场景,建议结合 RedLock 算法提升容错性1216。