在前面可重入锁加锁一文中,我们可以知道当锁存在时,是会加锁失败的,即 Hash 的 key 存在, field 也存在,但 field 对应的 value 不是当前线程生成的这种情况。
所以本文看一下这种加锁失败的情况Redisson会怎样处理呢?
再看加锁 Lua 脚本
1 | if (redis.call('exists', KEYS[1]) == 0) then |
在 lua 脚本中,前两段 if 分别排除了两种情况:
- 锁不存在;
- 锁存在且是自己线程(可重入);
剩下的情况就是锁存在,但是不是自己线程锁,也就意味着加锁失败。
对于这种情况,会执行 pttl 命令,返回锁的剩余时间。
加锁失败后的处理
查看RedissonLock
类中lock(long leaseTime, TimeUnit unit, boolean interruptibly)
这个方法的源码。
先来看开头一部分:返回值ttl若为null,说明加锁成功,方法直接返回。
再看下面获取锁失败之后的逻辑:在一个while (true)循环里一直调用 tryAcquire 方法,直到加锁成功!
总结
- 可重入锁的互斥是依靠 Redis Lua 脚本来保证的;
- 加锁失败会返回当前锁的剩余时间;
- 加锁失败后,会在 Java 代码中使用 while 循环一直尝试加锁。
大概的流程,如下图: