Skip to content
困难

一句话答案

Redisson 用 Lua 脚本实现可重入锁,Watch Dog 每 10s 自动续期 30s 防止业务未完成锁过期。

核心要点

Redisson 加锁的 Lua 脚本:

lua
-- tryLockInnerAsync 中的加锁脚本
if (redis.call('exists', KEYS[1]) == 0) then
    -- 锁不存在,创建并初始化(Hash 结构:key=锁名, field=threadId, value=重入次数)
    redis.call('hset', KEYS[1], ARGV[2], 1);
    redis.call('pexpire', KEYS[1], ARGV[1]);
    return nil;  -- 加锁成功返回 nil
end;

if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then
    -- 同一线程重入,计数+1
    redis.call('hincrby', KEYS[1], ARGV[2], 1);
    redis.call('pexpire', KEYS[1], ARGV[1]);
    return nil;  -- 重入成功返回 nil
end;

return redis.call('pttl', KEYS[1]);  -- 加锁失败,返回剩余过期时间

Lua 脚本保证并发安全的原因:

  • Redis 是单线程执行命令,Lua 脚本在 Redis 内部是原子执行的
  • 执行 Lua 脚本期间,Redis 不会执行其他客户端的命令
  • 因此 "判断 + 设置" 整个操作是原子的,不会有竞态条件

Watch Dog(看门狗)续期机制:

加锁成功后(默认锁超时 30s):
  → 启动一个定时任务(每 30s/3 = 10s 执行一次)
  → 检查持锁线程是否仍在运行(锁是否仍存在)
  → 是 → 重新设置过期时间为 30s(续期)
  → 否 → 停止续期任务

当持锁线程正常执行完毕并释放锁后:
  → 取消续期任务

当持锁线程宕机:
  → JVM 进程退出,续期任务停止
  → 锁在 30s 后自动过期,其他线程可以获取
追问与易错

追问方向:

  • Watch Dog 会无限续期吗?
  • 锁过期时间设多少?
  • RedLock 还推荐吗?

易错点:

  • ❌ 用了 Redisson 就万事大吉——主从切换仍可能丢锁
  • ❌ Watch Dog 是定时线程——是 Netty TimerTask

💡 记忆锚点

Redisson锁 = 自助停车场:Lua脚本是原子闸机(进出一气呵成),Hash存车位号+重入次数(同一辆车可反复进出),看门狗每10s巡逻一次帮你续费30s停车时间,车开走(JVM退出)则自动到期释放车位。