- 获取锁
<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));
}
-- 如果键名为 KEYS[1] 的键不存在
if (redis.call('exists', KEYS[1]) == 0) then
-- 将键名为 KEYS[1] 的哈希表中 ARGV[2] 字段的值加上 1
redis.call('hincrby', KEYS[1], ARGV[2], 1);
-- 设置键名为 KEYS[1] 的过期时间为 ARGV[1] 毫秒
redis.call('pexpire', KEYS[1], ARGV[1]);
-- 返回 nil
return nil;
end;
-- 如果键名为 KEYS[1] 的哈希表中存在 ARGV[2] 字段
if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then
-- 将键名为 KEYS[1] 的哈希表中 ARGV[2] 字段的值加上 1
redis.call('hincrby', KEYS[1], ARGV[2], 1);
-- 设置键名为 KEYS[1] 的过期时间为 ARGV[1] 毫秒
redis.call('pexpire', KEYS[1], ARGV[1]);
-- 返回 nil
return nil;
end;
-- 返回键名为 KEYS[1] 的键的剩余过期时间(以毫秒为单位)
return redis.call('pttl', KEYS[1]);
这段代码的作用是:如果不存在指定的键(分布式锁),则创建该键并将指定字段的值加1,设置过期时间并返回 nil;如果存在指定的键和字段,则将该字段的值加1并更新过期时间,返回 nil;如果存在指定的键但不存在指定的字段,则返回键的剩余过期时间(以毫秒为单位)。
2. 释放锁
protected RFuture<Boolean> unlockInnerAsync(long threadId) {
return evalWriteAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then " +
"return nil;" +
"end; " +
"local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); " +
"if (counter > 0) then " +
"redis.call('pexpire', KEYS[1], ARGV[2]); " +
"return 0; " +
"else " +
"redis.call('del', KEYS[1]); " +
"redis.call('publish', KEYS[2], ARGV[1]); " +
"return 1; " +
"end; " +
"return nil;",
Arrays.asList(getRawName(), getChannelName()), LockPubSub.UNLOCK_MESSAGE, internalLockLeaseTime, getLockName(threadId));
}
-- 如果键名为 KEYS[1] 的哈希表中不存在字段 ARGV[3]
if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then
-- 返回 nil
return nil;
end;
-- 将键名为 KEYS[1] 的哈希表中字段 ARGV[3] 的值减去 1
local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1);
-- 如果哈希表中字段 ARGV[3] 的值仍然大于 0
if (counter > 0) then
-- 设置键名为 KEYS[1] 的过期时间为 ARGV[2] 毫秒
redis.call('pexpire', KEYS[1], ARGV[2]);
-- 返回 0
return 0;
else
-- 删除键名为 KEYS[1] 的键
redis.call('del', KEYS[1]);
-- 向频道 KEYS[2] 发布消息 ARGV[1]
redis.call('publish', KEYS[2], ARGV[1]);
-- 返回 1
return 1;
end;
-- 返回 nil
return nil;
这段代码的作用是:首先判断指定的键和字段是否存在,如果不存在则返回 nil;如果存在,则将指定字段的值减1,并判断减1后是否大于0,如果大于0则设置键的过期时间并返回0,表示锁已被释放但仍有其他客户端持有;如果减1后的结果小于等于0,则删除该键并向指定频道发布消息,表示锁已被完全释放,返回1。