先了解下整体流程,如下图
这里简单归纳下Redisson分布式锁原理:
编写debug测试用例,开始debug
查看tryLock实现
点击tryAcquire查看获取锁方法
再点击实现方法(这里从名称命名可以看出该方法为异步方法)
判断时间是否为负一来确定是否要设置默认值,再点击tryLockInnerAsync获取锁方法实现源码
源码内容:在当前的线程域中记录内部锁释放时间,用lua脚本来获取锁。
lua脚本内容:判断锁的key是否不存在,如果不存在就记录锁标识并设置锁重入次数加一,然后设置锁的有效期,返回nil结束;判断锁的key是否是自己的,如果是我自己的锁重入次数加一,然后设置有效期,返回nil结束;如果上述都失败返回失败结果。(pttl获取对应值的剩余有效期,毫秒为单位)
返回上级方法
获取完锁后判断返回值是否为空,然后用当最大等待时间减去消耗时间来获取剩余时间,如果等待时间小于获取锁消耗的时间那么返回false;如果还有剩余时间那么再次获取当前时间,在subscribe方法里订阅锁释放信息,再判断(412行)能不能在剩余时间内获取到锁释放信息
然后再往下走(425行)获取剩余时间
进入无限循环-》尝试获取锁-》 获取剩余时间进行判断-》没过时,判断ttl大于0小于剩余时间用subscribeFuture在ttl的时间内尝试获取锁,反之用subscribeFuture在剩余时间内尝试获取锁-》判断剩余时间是否大于0-》如果大于0继续循环下去
锁超时问题(锁续命)
万一业务阻塞ttl到期被其他线程获取到
再看回之前的锁获取方法中,当RFuture回调完成后调用onComplete如果ttl为空代表获取锁成功执行到期更新功能(258行)
点开执行到期更新方法,程序把所有锁放到一个静态map中以业务名称作为key用putIfAbsent放置进去,这里考虑到锁重入的问题putIfAbsent可以保证获取到的是同一个entry,接着就用renewExpiration去更新有效期
可以看到有个定时任务在初始过期时间的三分之一后执行
执行的内容:从map中拿出Entry获取线程id刷新有效期(renewExpirationAsync),点开renewExpirationAsync查看
lua脚本内容:判断当前的锁是不是这个线程拿的,如果判断成功则尝试更新有效期
future执行完成后调用renewExpiration方法,也就是递归(自己调自己)
最后把执行后的任务(TimeOut)放到entry里面去
查看unlock方法
查看unlockAsync方法
查看cancelExpirationRenewal(取消到期更新)方法
移除map中对应entry的线程,然后把entry里的TimeOut任务给取消掉,最后将map中的entry移除,到此结束。
评论