(1). 概述
在前面使用了,RLock进行分布式锁的入门,在这里,对RLock进行深入源码剖析.
RedissonLock(非公平锁)是RLock的实现之一.
(2). RedissonLock
<T> RFuture<T> tryLockInnerAsync(long waitTime, long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {
return evalWriteAsync(getRawName(), LongCodec.INSTANCE, command,
"if (redis.call('exists', KEYS[1]) == 0) then " +
"redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
"redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
"return redis.call('pttl', KEYS[1]);",
Collections.singletonList(getRawName()), unit.toMillis(leaseTime), getLockName(threadId));
}
(3). lock(lua)脚本
## 注意:Lua脚本的下标是从1开始的
# KEYS[1] = "anyLock" // redis中的key
# ARGV[1] = 10000 // 看门狗,续租的时间(ms)
# ARGV[2] = 48575bd6-4e6d-4485-8f61-255063d81d54:47 // 唯一ID:线程ID
# 判断key是否存在(0:不存在 1:存在)
# EXISTS 'anyLock'
if (redis.call('exists', KEYS[1]) == 0) then
# 创建Hash数据结构,并为Hash数据结构,设置过期时间
# HINCRBY 'anyLock' '48575bd6-4e6d-4485-8f61-255063d81d54:47' 1
redis.call('hincrby', KEYS[1], ARGV[2], 1);
# PEXPIRE 'anyLock' 10000
redis.call('pexpire', KEYS[1], ARGV[1]);
return nil;
end;
# 在Hash表中判断field和value是否存在(0:不存在 1:存在)
# HEXISTS 'anyLock' '48575bd6-4e6d-4485-8f61-255063d81d54:47'
if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then
# key在Hash中存在的情况下.
# 让Hash中的key(anyLock),field('48575bd6-4e6d-4485-8f61-255063d81d54:47')进行自增.
# HINCRBY 'anyLock' '48575bd6-4e6d-4485-8f61-255063d81d54:47' 1
redis.call('hincrby', KEYS[1], ARGV[2], 1);
# 重新设置过期时间
redis.call('pexpire', KEYS[1], ARGV[1]);
return nil;
end;
# 以毫秒为单位,返回:key的过期时间.
# PTTL 'anyLock'
return redis.call('pttl', KEYS[1]);
(4). unlock(lua)脚本
KEYS[1] = 'anyLock'
KEYS[2] = redisson_lock__channel:{anyLock}]
ARGV[1] = 0
ARGV[2] = 10000
ARGV[3] = 'afc990dd-79b6-4d48-b07e-d900796d7691:48'
# 1. 判断锁是否存在(0:不存在 1:存在)
# HEXISTS 'anyLock' 'afc990dd-79b6-4d48-b07e-d900796d7691:48'
if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then
return nil;
end;
# 对Hash表中的key(anyLock),field(afc990dd-79b6-4d48-b07e-d900796d7691:48),实现自减.
# HINCRBY 'anyLock' 'afc990dd-79b6-4d48-b07e-d900796d7691:48' -1
local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1);
# 大于0,代表还有其它的线程在使用(这里用到了重入锁)
if (counter > 0) then
# 重新设置Hash过期时间
# PEXPIRE 'anyLock' 10000
redis.call('pexpire', KEYS[1], ARGV[2]);
return 0;
else
# 小于等于零的情况下,删除KEY,发布事件
# DEL 'anyLock'
redis.call('del', KEYS[1]);
# PUBLISH 'redisson_lock__channel:{anyLock}]' 0
redis.call('publish', KEYS[2], ARGV[1]);
return 1;
end;
return nil;
(5). 总结
RedissonLock是通过Redis+Lua来实现分布式锁的,而且,还实现了重入锁.但是,RedissonLock是一个非公平锁,公平锁有排队功能,后面会继续进行解剖.