Redisson分布式锁流程分析(4)可重入锁释放

前面已经分析了可重入锁的加锁,本节来看一下是怎么释放锁的。

主动释放

当线程完成一系列操作之后,我们都需要主动去释放锁,调用RedissonLock实例的unlock()方法即可以释放锁,查看源码可知最终调用到了 RedissonLock 中的 unlockInnerAsync(long threadId) 这个方法,该方法中用到了当前线程的id。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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));
}

分析一下方法里面用到的 lua 脚本。

  1. 如果锁不存在,直接返回 null;
  2. 如果锁存在,则对锁的重入次数 -1;
    1. 剩余重入次数大于 0,重新设置过期时间,返回 0;
    2. 剩余重入次数不大于 0,删除 redis key 并发布消息,返回 1;

主动释放锁这块考虑的不仅仅是对 key 进行处理,因为可能存在重入锁,所以会先对 key 对应的 hash 表中的 value 进行递减,相当于减去重入次数。

自动释放

和主动释放相比,自动释放的情况就更加简单了。比如下面两种情形:

  1. 当服务宕机时,看门狗不再看门,那么最多 30s 之后锁被自动释放;
  2. 当设置锁的时间,超时自动释放。
------ 本文完 ------