先加了写锁,后面再次加写锁或者读锁
anyLock: {
“mode”: “write”,
“UUID_01:threadId_01:write”: 2,
“UUID_01:threadId_01”: 1
}
写锁的释放lua脚本在这里
RedissonWriteLock.unlockInnerAsync()
比如说现在的参数是这
KEYS[1] = anyLock
KEYS[2] = redisson_rwlock:{anyLock}
ARGV[1] = 0
ARGV[2] = 30000
ARGV[3] = UUID_01:threadId_01:write
下面来分析一下lua脚本
local mode = redis.call(‘hget’, KEYS[1], ‘mode’);
if (mode == false) then
redis.call(‘publish’, KEYS[2], ARGV[1]);
这几行不用多说,先获取anyLock这个hash表中key为mode对应的值,如果不存在的话,锁肯定是已经释放或者过期了
if (mode == ‘write’) then
如果是写锁的话才会继续执行,不是的话直接返回1
local lockExists = redis.call(‘hexists’, KEYS[1], ARGV[3]);
if (lockExists == 0) then
判断anyLock这个hash表中key=UUID_01:threadId_01:write 是否存在,存在的话证明这个线程对应的写锁是存在的,不存在的话直接返回null
local counter = redis.call(‘hincrby’, KEYS[1], ARGV[3], -1);
if (counter > 0) then
redis.call(‘pexpire’, KEYS[1], ARGV[2]);
现在已经确定写锁是存在的,并且需要释放,那这个参数hincrby之前见过好多次了,就是增量更新命令,这里给的是-1,所以是将anyLock这个hash表中key=UUID_01:threadId_01:write,对应的value值-1,并且返回更新后的值。这里就是处理可重入锁的逻辑
如果这个更新后的值大于0的话,证明还有读锁需要释放,这个锁不能过期,那就更新一下过期时间。
redis.call(‘hdel’, KEYS[1], ARGV[3]);
走到这里的话,证明这个写锁没有重入,那就删除anyLock这个hash表中key=UUID_01:threadId_01:write的键值对。
if (redis.call(‘hlen’, KEYS[1]) == 1) then
redis.call(‘del’, KEYS[1]);
redis.call(‘publish’, KEYS[2], ARGV[1]);
这个命令就很有意思了,hlen命令是获取anyLock这个hash表中还有多少键值对,如果是1个的话,那肯定是只剩下mode这个key了,删除这个anyLock,广播一下就结束了
但是如果大于1个的话,就说明还有其他的key
那什么情况下还会有多余的key呢,写锁是互斥的,只能重入,但是可重入的逻辑在上面已经处理过了。那这里的其他key就只能是这个线程后来加的读锁了。
所以这里就是为了处理写锁+读锁的情况
redis.call(‘hset’, KEYS[1], ‘mode’, ‘read’);
如果释放完写锁,还存在其他锁,那这个锁一定是读锁,所以就将mode变成read,此时这个写锁就完全变成读锁了,等待读锁逻辑的处理。