很多人都在使用基于redis的分布式锁。 今天,我们将简要介绍基于redison客户端的分布式锁定源代码分析。 具体内容如下。
另一方面,基于redis分布式锁定源代码分析1、使用redis分布式锁定1 )、redison客户端创建分布式锁定工具。 具体代码如下图所示。
从图1可以看出,该工具类的主要内容是初始化redisson客户端、进行锁定、解除锁定三个操作。
2 )使用RedissonLockUtils锁定业务代码,处理业务后解锁。 具体代码如下图所示。
从图2中可以看到,解锁操作位于finally块中,而不是紧接在业务代码之后。 这是为了防止业务代码异常结束、锁定被解除。
2、redis锁的源代码分析
1 )、找到redissonclient trylock方法的具体实现源代码。 下图:
从图3中可以看到,tryLock方法中的主要操作是调用tryAcquire尝试锁定,如果锁定不成功,则判断到目前为止锁定所用的时间是否超过了锁定等待时间waitTime,如果超过,则返回false
2 )、下面的图片显示tryAcquire方法的源代码。
从图4可以看出,在施加锁定之前,判断用户进行锁定操作的时候是否有传递锁定的超时时间,在没有的情况下默认为30秒。 然后调用tryAcquireAsync方法进行锁定。
3 ),让我们看看tryAcquireAsync方法的源代码,如下图所示。
从图4可以看出,这里的锁通过执行Lua脚本,将为key赋值的操作和为key设置超时时间的操作合并为一个操作,保证了操作的原子性。 这样,虽然为key分配了值,但不会出现未设定超时时间的问题。
二.续锁方案
上面介绍了如何使用redis分布式锁以及如何分析锁定的源代码。 现在,让我们先来看看问题。 锁定业务代码。 在运行业务代码时,锁定超时时间到了,锁定被释放。 此时,该线程的业务逻辑尚未处理。 此时,其他线程获得锁定会引起各种问题。 针对这种问题,需要在接近超时时间时继续进行锁定操作(即,对锁定重新设定超时时间)。 持续的锁定计划包括:
1、redission看门狗自动延期机制。
Redisson内部有一个监视程序,用于监视锁定,以在Redisson实例关闭之前延长锁定超时时间。 让我们先看看tryAcquire的源代码。 下图:
从图6可以看到,如果我们没有设定锁定超时时间,则自动设定超时时间,默认值为30秒。 下图:
自动设置超时时间锁定和我们设置超时时间锁定的区别在于,自动设置超时时间锁定后,启动看门狗(watch dog ),每隔一段时间进行检查,业务1仍有锁定密钥时,锁定具体操作为scheduleexpirationrenewal (threadid ),源代码如下图所示。
使用这个方法时需要注意。 如果锁定的业务代码保持被阻止,锁定将保持被占用,无法释放。
2、定制的摇头丸。
通常,使用分布式锁定时,根据业务需要,在锁定时设置合理的超时时间。 但是,如果设定了锁定超时时间,则不会启动计划1的“监视程序”(watch dog )自动延期机制。 此时,需要自己设计持续锁定方案。 在设置连续锁定方案之前,让我们先看看此锁定是如何存储在redis中的,如下图所示。
其实自定义持久锁定计划其实和看门狗(watch dog )的自动延期机制相同,就是在锁定期间打开另一个线程调用持久锁定的代码。 具体代码如下图所示。
下面介绍一下接下来的代码。 主要步骤如下:
1 )基于密钥key获取具有密钥的线程的key中的字段和值。
2 )根据自己设置的锁定超时时间,定义自旋时间。
3 )、开始旋转,重新获取当前redis的锁定密钥字段和值。
4 )查看再次获取的字段和值是否存在,如果不存在,则结束继续锁定操作。 如果存在,则进入下一步。
5 )判断当前锁定密钥的字段名和需要继续锁定密钥的字段名是否相同,否则可以结束继续锁定操作。 同样地进行下一步。
6 )、获取锁定的剩馀时间,判断剩馀时间是否小于锁定超时时间的1/4。 是的,重新设置超时时间,使具有锁定的线程继续具有锁定。
7 )、是否需要锁定,每超时时间的1/4进行锁定继续的判断。
测试上面的后续代码。 测试代码如下。
现在,让我们来看看redis的key剩下的时间。 下图:
从这张图可以看出,重新锁定成功了。 该持续锁定计划可以根据自己的需要设置合理的超时时间,对于持续锁定,还可以设置持续锁定操作的超时时间,以确保拥有锁定的线程继续被阻止,并且锁定保持被占用而不被释放
这篇文章转载自微信公众号。 程序猴子共享编程