Redisson重入原理

在上篇文章我们已经知道了除了需要存储线程标识外,会额外存储一个重入次数。那么接下来我们查看使用Redisson时,Redisson加锁与释放锁流程图

当开始获取锁时,会先判断是否存在,如果存在再进行判断锁标识是否是当前线程,如果是那么value值 +1 代表锁重入次数加 1 并重新设置过期时间,如果不存在,那么直接获取锁并存储在Redis中,设置超时时间。如果需要释放锁,仍然是先获取标识是否当前线程一致,如果不一致那么说明锁已经超时释放,如果一致则对value值-1后再判断value是否为0,如果不是说明进行了锁重入,那么重置锁的超时时间即可。如果已经是0了,那么直接释放锁即可

以上复杂业务使用Java已经不能满足了,因此这部分业务在Redisson中使用了Lua脚本实现

获取锁的Lua脚本

释放锁的Lua脚本

接下来我们可以进行源码跟踪查看可重入锁的实现

查看基本tryLock()方法

接下来我会分批给出tryLock()方法源码

接下来查看tryAcquire()方法查看如何获取到锁

这里做了leaseTime值判断,实际上是判断调用者是否传递了锁释放时间,如果没有传入锁施放时间那么默认值为-1,这里我们查看任意一个tryLockInnerAsync()方法可以

可以看到tryLockInnerAsync()方法就是通过lua脚本实现获取锁并进行重入的,有一点是和我们上面图片中的不同,那就是获取锁失败后会返回当前锁的过期时间。

查看unlockAsync()方法,追踪到最底层代码如下

那么接下来依然是追踪源码,上文中获取锁失败的源码如下

这里会返回一个当前锁的施放时间,那么回退一层查看我们得到过期释放时间后要去做什么

接着回退查看上一层代码接着做了什么事情

这里get()方法获取到了返回的有效期值。接着回退上一层代码就到达了tryLock()方法,具体代码注释如下

internalLockLeaseTime属性存在一个默认值,如果我们不指定锁的过期时间,那么就是使用Redisson中的默认值,具体源码如下

接着我们查看定期更新锁的有效期方法scheduleExpirationRenewal(),具体源码如下

接下来我们查看续约方法renewExpiration()

renewExpirationAsync()方法作用就是刷新锁的有效时间,具体源码如下

取消续约定时任务的具体代码如下

对锁重试与看门狗机制进行一个流程总结 

总结 

可重试:利用信号量和PubSub功能实现等待、唤醒、获取锁失败的重试机制。

超时续约:利用watchDog,每隔一段时间,重置超时时间。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注