redis面试(十四)公平锁可重入

发布于:2024-08-17 ⋅ 阅读:(89) ⋅ 点赞:(0)

可重入

就是当前线程多次加锁
while true,lindex redisson_lock_queue:{anyLock} 0,获取队列第一个元素,判断一下他的timeout时间是否大于当前时间了,假设当前时间是10:00:08,此时肯定是是不成立的,假设就直接跳出死循环

当前锁是否不存在,不成立;hexists anyLock UUID_01:threadId_01,在anyLock hash中,是否存在一个UUID_01:threadId_02的key,当前这个锁是否是客户端A加锁,成立,hincrby给加锁次数累加1,重新pexpire刷新锁key的生存时间为30000毫秒,返回一个nil

此时可重入加锁成功,无非就是累加了1次加锁的次数

分数刷新

在排队中的客户端,模拟等待一段时间后,再次尝试加锁。

第二个线程第二次尝试加锁

客户端B,10:00:00,10:00:15,他来再次尝试进行加锁,但是客户端A此时还是持有着这把锁的,此时会出现什么情况呢?

while true,获取队列第一个元素,同时获取这个元素的timeout时间,10:00:25 <= 10:00:15?不成立,while死循环退出

判断一下是否没人加锁,以及判断是否是客户端B进行的加锁,都不成立

ttl = 10:00:25 - 10:00:15 = 10000毫秒
timeout =10000毫秒 + 10:00:15 + 5000毫秒 = 10:00:30

zadd redisson_lock_timeout:{anyLock} 10:00:30 UUID_02:threadId_02,刷新一下有序集合中的元素的分数,10:00:30

大致可以理解为,你的某个客户端不是在不断的重试尝试加锁么?每次重试尝试加锁的时候,就判定为是这个客户端一次新的尝试加锁的行为,此时会将这个客户端对应的timeout时间往后延长,10:00:25,这次他重试加锁之后,timeout时间算出来就变成10:00:30,把这个客户端的timeout时间延长了,有序集合中的分数变大了

if redis.call(‘zadd’, KEYS[3], timeout, ARGV[2]) == 1 then

zadd指令的返回值,如果是第一次往里面怼入一个元素,返回值是什么?如果是第二次刷新这个元素的分数,返回值是什么?如果是第一次插入一个元素在有序集合中,此时就会返回值是1,同时会入队;但是后续不断的尝试加锁的时候,其实是会不断的刷新这个有序集合中的元素的分数,越来越大,但是每次刷新分数,返回值是0

所以不会重复的往队列中插入这个元素的

第三个线程第二次尝试加锁

客户端C,10:00:20,再次尝试加锁

10:00:30 < 10:00:20?不成立;尝试加锁,都不成立

再次刷新他的timeout分数

ttl = 10:00:30 - 10:00:20 = 10000毫秒
timeout = 10000毫秒 + 10:00:20 + 5000毫秒 = 10:00:35

zadd redisson_lock_timeout:{anyLock} 10:00:35 UUID_03:threadId_03

还是维持着跟之前一样的这么一个顺序,客户端B的分数会刷大,客户端C的分数其实也在不断的刷大,所以在有序集合中的分数的大小的顺序,基本上还是按照的是最初他们是如何排队的,此时也会如何排队