【Redisson】锁可重入原理
目录
一、基本原理
二、源码解析:
(2)获取锁
(1)释放锁:
之前给大家介绍过redisson的分布式锁,用redisson来实现比自己手搓简单的分布式锁有很多好处,因为这些可重入、可重试的逻辑较为复杂,他们的lua脚本不可能让我们在开发时自己实现,这样太耗时间了。所以redisson就帮我们实现了可重入和可重试。但我们也要知道他的原理,这期我们先讲可重入。
上一篇:
【Redisson】快速实现分布式锁-CSDN博客
一、基本原理
基本原理:
(1)获取锁的时候,还是使用setnx命令,如果该锁还没有被获取过,直接set,也就是获取锁成功
(2)当该线程第二次获取锁时,因为锁已经被获取了,也就是setnx返回false。这时候,先不直接返回获取锁失败的逻辑,而是先判断该锁的value值是不是自己,如果是,那么就获取锁成功。
(3)有一个计数器,每次获取锁成功计数器就+1,每次释放锁的时候计数器就-1。当计数器为0的时候表明该线程所有重入的锁都被释放完毕了,就可以删除这个key。那么其他线程就可以获取锁了
(4)因为key的value值既要记录线程标识,也要记录重入次数。所以String类型的结构就不满足了。需要使用到hash结构
(5)注意:每次释放锁时,如果value值不是0,说明该锁还是被该线程占用的。也就是释放重入锁的时候,要重置锁的有效期
图解:
二、源码解析:
(2)获取锁
<T> RFuture<T> tryLockInnerAsync(long waitTime, long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {return this.commandExecutor.syncedEvalNoRetry(this.getRawName(), LongCodec.INSTANCE, command, "local mode = redis.call('hget', KEYS[1], 'mode');" +" if (mode == false) then " +" redis.call('hset', KEYS[1], 'mode', 'read');" +" redis.call('hset', KEYS[1], ARGV[2], 1);" +" redis.call('set', KEYS[2] .. ':1', 1);" +" redis.call('pexpire', KEYS[2] .. ':1', ARGV[1]);" +" redis.call('pexpire', KEYS[1], ARGV[1]);" +" return nil;" +" end;" +" if (mode == 'read') or (mode == 'write' and redis.call('hexists', KEYS[1], ARGV[3]) == 1) then" +" local ind = redis.call('hincrby', KEYS[1], ARGV[2], 1);" +" local key = KEYS[2] .. ':' .. ind;redis.call('set', key, 1);" +" redis.call('pexpire', key, ARGV[1]);" +" local remainTime = redis.call('pttl', KEYS[1]);" +" redis.call('pexpire', KEYS[1], math.max(remainTime, ARGV[1]));" +" return nil;" +" end;" + "return redis.call('pttl', KEYS[1]);",Arrays.asList(this.getRawName(), this.getReadWriteTimeoutNamePrefix(threadId)), new Object[]{unit.toMillis(leaseTime), this.getLockName(threadId), this.getWriteLockName(threadId)});}
解析:
(1)释放锁:
解析: