@Override
public void unlock() {
//解锁成功返回true
Boolean opStatus = get(unlockInnerAsync(Thread.currentThread().getId()));
if (opStatus == null) {
throw new IllegalMonitorStateException("attempt to unlock lock, not locked by current thread by node id: "
+ id + " thread-id: " + Thread.currentThread().getId());
}
if (opStatus) {
//取消定时任务
cancelExpirationRenewal();
}
}
第一步:发布解锁消息删除key
protected RFuture<Boolean> unlockInnerAsync(long threadId) {
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"if (redis.call('exists', KEYS[1]) == 0) then " +
"redis.call('publish', KEYS[2], ARGV[1]); " +
"return 1; " +
"end;" +
"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.<Object>asList(getName(), getChannelName()), LockPubSub.unlockMessage, internalLockLeaseTime, getLockName(threadId));
}
调用lua脚本,exists命令:若 key 存在返回 1 ,否则返回 0 。
publish 发布unlockMessage消息
hexists 如果哈希表含有给定字段,返回 1 。 如果哈希表不含有给定字段,或 key 不存在,返回 0 。
hincrby Redis Hincrby 命令用于为哈希表中的字段值加上指定增量值,此处是-1即减1,因为存在重入锁问题,N次上锁需要N次解锁
del 删除key
第二步:取消定时任务
void cancelExpirationRenewal() {
//移除过期时间重置Map中的数据 并返回对应value
Timeout task = expirationRenewalMap.remove(getEntryName());
if (task != null) {
//取消任务
task.cancel();
}
}
private static final ConcurrentMap<String, Timeout> expirationRenewalMap = PlatformDependent.newConcurrentHashMap();
调用lock(),tryLock()无参方法会生成一个定时任务,手动unlock的时候会取消任务