Redisson实现可重入锁原理

Redisson底层实现分布式锁是采用hash结构存储锁,

其中Key代表锁名,也是一把锁的唯一标识,key存在说明此时这把锁已经被持有了

Value中的key按照id + “:” + threadId命名,作为当Key一致时,即有线程想获取同一把锁时,分辨是否是当前锁的进程,如果不是,则加锁失败

Value中的小value作为锁的计数器,每次线程获取锁,则加1,释放锁就减1,只有同一线程中才可以重入同一把锁,每重入一次,value就计数一次

下面是加锁的lua脚本代码

1
2
3
4
5
6
7
8
9
10
11
"if (redis.call('exists', KEYS[1]) == 0) then " +
"redis.call('hset', 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]);"

参数有三个:

KEYS[1] : 锁名称

ARGV[1]: 锁失效时间

ARGV[2]: id + “:” + threadId; 锁的小key

可以看到,它先判断锁是否存在,如果不存在则直接获取锁,将传入的信息以hash的形式存入。

若锁存在,则取其中的threadId,与传入的threadid对比,一致则另计数器加1代表重入该锁一次

若比对失败,返回nil

释放锁逻辑和加锁类似

参数有三个:

KEYS[1] : 锁名称

ARGV[1]:线程唯一标识

ARGV[2]: 锁的自动释放时间

首先判断是否是自己的锁,不是则返回nil

是自己的则将计数器减1

然后判断计数器是否大于0,是则更新锁的释放时间

不是则说明已经没有操作在持有锁了,则根据key删除锁