一、使用
1、pom.xml导入依赖
2、配置文件
3、使用类
二、原理
obtain方法
主要是根据lockKey去查locks这个map中是否已经存在这个key
如果存在就返回内部类RedisLock
如果不存在就创建一个RedisLock,以lockKey为key,RedisLock为value放入map中
备注:每个分布式应用自己都会创建一个RedisLockRegistry实例,同一个应用的多个线程共享RedisLock类
tryLock方法
主要过程
先获得本地锁,拿不到直接返回失败
当前时间还没过期并且还没拿到redis锁,睡眠100ms继续重试
如果拿到redis锁,结束循环,返回成功
如果超时了还没拿到,释放锁,返回失败
拿redis锁的过程
通过obtainLock方法,执行lua脚本来获取
redisTemplate.execute()参数说明:
第一个obtainLockScript参数就是要执行的lua脚本;
第二个参数就是表示在脚本中所用到的那些 Redis 键(key),这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用1为基址的形式访问( KEYS[1] , KEYS[2] ,以此类推);
第三个参是附加参数 arg [arg …] ,可以在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似( ARGV[1] 、 ARGV[2] ,诸如此类)
为什么要用本地锁
- 为了可重入
- 为了减轻redis服务器的压力
为什么要用lua脚本
- 保证原子性
- 减少网络开销
- 替代redis的事务功能
unlock方法
释放锁的过程
1、判断是否是当前线程持有锁,如果不是,抛异常(本地锁)
2、判断当前线程持有锁的计数
如果当前线程持有锁的计数 > 1,说明本地锁被当前线程多次获取,这时只会释放本地锁,释放之后当前线程持有锁的计数-1。
否则,释放本地锁和redis锁。