Redisson 中的分布式锁​​既支持阻塞行为,也支持非阻塞行为​​,具体取决于你调用的加锁方法。下面我用一个表格帮你快速了解不同方法的行为,然后再详细解释其背后的机制和最佳实践。

方法签名

锁类型

行为描述

是否自动续期 (看门狗)

备注

void lock()

​阻塞​

​一直阻塞​​当前线程,直到获取到锁。

是 (默认30秒)

最常用,需手动解锁

void lock(long leaseTime, TimeUnit unit)

​阻塞​

​一直阻塞​​直到获取锁,但​​不使用​​看门狗续期,锁在指定的 leaseTime后自动过期。

需确保业务在 leaseTime内完成

boolean tryLock()

非阻塞

​立即返回​​(仅尝试一次)。成功返回 true,失败返回 false

是 (默认30秒)

boolean tryLock(long waitTime, long leaseTime, TimeUnit unit)

​可超时阻塞​

​尝试获取锁​​,在指定的 waitTime内会阻塞等待;若超过 waitTime仍未获锁,则返回 false。获锁后,将在 leaseTime后自动释放。

leaseTime> 0 时:否​

灵活,可同时控制等待时间和持有时间

boolean tryLock(long waitTime, TimeUnit unit)

​可超时阻塞​

​尝试获取锁​​,在指定的 waitTime内会阻塞等待。获锁后,​​使用看门狗自动续期​​。

是 (默认30秒)

推荐使用,兼顾等待和锁安全

⚙️ 阻塞锁的实现原理

(pub/sub可以参考我另一篇帖子Redis pub/sub机制-CSDN博客

Redisson 并未采用简单的循环重试(自旋),而是通过 ​​Redis 的发布订阅(Pub/Sub)机制​​ 实现高效的阻塞等待,这能有效减少不必要的网络开销和 Redis 压力

。其工作流程如下:

  1. 1.

    ​尝试加锁​​:线程尝试获取锁。

  2. 2.

    ​订阅频道​​:如果锁已被占用,当前线程会​​订阅​​这个锁对应的特定频道。

  3. 3.

    ​阻塞等待​​:线程进入阻塞状态,等待消息。

  4. 4.

    ​收到通知​​:当持有锁的线程释放锁(通过 unlock)时,它会向这个频道​​发布​​一条“锁已释放”的消息。

  5. 5.

    ​唤醒重试​​:所有订阅了该频道的线程会被唤醒,并重新尝试竞争获取锁。

  6. 6.

    ​超时控制​​:如果在指定的 waitTime内仍未获锁,线程会停止等待并返回 false

⚠️ 重要机制:看门狗(Watchdog)与续期

这是一个需要特别注意的核心机制,它直接关系到锁的安全性和业务稳定性:

  • ​作用​​:为了防止业务执行时间过长导致锁​​超时自动释放​​,进而引发数据混乱,Redisson 为没有明确指定 leaseTime的锁提供了看门狗机制

  • ​工作方式​​:默认情况下,锁的超时时间是 ​​30秒​​。看门狗会每隔一段时间(通常是超时时间的 1/3,即 10 秒)检查持有锁的线程是否还在运行。如果还在运行,它会​​自动将锁的超时时间重新重置为 30秒​​。

  • ​守护线程​​:看门狗线程被设置为​​守护线程​​,这意味着如果业务线程挂掉,JVM 会随之终止看门狗线程,避免了因续期线程存活而导致锁永远无法释放的问题

  • ​最佳实践​​:

    • 如果你的​​业务执行时间不确定​​,使用默认的 lock()或 tryLock(long waitTime, TimeUnit unit),让看门狗来管理锁的过期时间,这是最安全省心的方式。

    • 如果你的​​业务执行时间非常确定​​,可以使用 lock(long leaseTime, TimeUnit unit)或 tryLock(long waitTime, long leaseTime, TimeUnit unit)并传入一个大于业务时间的 leaseTime,然后等待锁自动释放。

📜 可重入性

Redisson 的分布式锁是​​可重入锁​​(Reentrant Lock)。这意味着同一个 JVM 中的同一个线程可以多次获取同一把锁,而不会被自己阻塞

。其内部通过一个​​锁计数器​​(存储在 Redis Hash 结构中)来实现。每次重入锁,计数器加一;每次释放锁,计数器减一。只有当计数器减为零时,锁才会被真正释放给其他线程。

💡 使用建议

  1. 1.

    ​首选 tryLock并设置超时​​:推荐使用 tryLock(long waitTime, TimeUnit unit)方法。它允许你指定一个合理的等待时间,避免了无限期阻塞导致系统雪崩,同时又享有看门狗自动续期的安全保障。

  2. 2.

    ​务必在 finally块中解锁​​:为了确保锁在任何情况下(即使业务异常)都能被释放,lock.unlock()操作必须放在 finally代码块中执行。

  3. 3.

    ​评估业务耗时​​:根据业务的预期执行时间,决定是依赖看门狗还是手动设置租期。对于耗时极短的操作,手动设置租期可以减少对 Redis 的请求。

  4. 4.

    ​理解主从架构风险​​:在 Redis 主从复制模式下,存在主节点宕机后数据未同步到从节点,导致锁“丢失”的极端情况。如需更高一致性保障,可了解 ​​RedLock 算法​​,但其实现复杂且有争议,需谨慎评估

希望这份详细的解释能帮助你更好地理解和使用 Redisson 的分布式锁。

Logo

更多推荐