文章目录
- 一.Redisson介绍
- 二.分布式锁的运用
- 1.引入依赖.
- 2.增加配置类.
- 3.简单代码实现
- 1.不指定加锁时间,会默认启动看门狗.自动帮你的锁进行续期.
- 2.指定加锁时间,不启用看门狗续期,到期自动解锁.
- 三.分布式锁实现原理
- 加锁过程
- 看门狗续期过程
一.Redisson介绍
Redisson 是架设在 Redis 基础上的一个 Java 驻内存数据网格(In-Memory Data Grid)。充分的利用了 Redis 键值数据库提供的一系列优势, 基于 Java 实用工具包中常用接口,为使用者提供了一系列具有分布式特性的常用工具类。 使得原本作为协调单机多线程并发程序的工具包获得了协调分布式多机多线程并发系统的能力,大大降低了设计和研发大规模分布式系统的难度。同时结合各富特色的分布式服务,更进一步简化了分布式环境中程序相互之间的协作。
以上是官网的介绍,主要就是基于redis分布式锁实现了jvm ReentrantLock锁的几乎所有功能, 读写锁,重入锁,公平锁,信号量等等.让你就像调用本地锁一样简单.可以说非常强大.
官方文档:Redisson
二.分布式锁的运用
1.引入依赖.
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.12.0</version>
</dependency>
2.增加配置类.
@Configuration
public class RedissonConfig {
@Bean
public RedissonClient redissonClient(){
Config config = new Config();
//集群配置
// config.useClusterServers()
// .setScanInterval(2000) // 集群状态扫描间隔时间,单位是毫秒
// //可以用"rediss://"来启用SSL连接
// .addNodeAddress("redis://127.0.0.1:7000", "redis://127.0.0.1:7001")
// .addNodeAddress("redis://127.0.0.1:7002");
//单节点配置
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
return Redisson.create(config);
}
}
3.简单代码实现
注意:此分布式锁默认实现均为可重入锁,和jvm锁一样,持有当前锁的线程可以重复获取锁
1.不指定加锁时间,会默认启动看门狗.自动帮你的锁进行续期.
@Autowired
RedissonClient redissonClient;
public void test(){
//传入的名称要注意,名称一样即为同一把锁
RLock lock = redissonClient.getLock("lock");
lock.lock();
try{
//执行具体的业务逻辑
}finally {
lock.unlock();
}
}
2.指定加锁时间,不启用看门狗续期,到期自动解锁.
@Autowired
RedissonClient redissonClient;
public void test(){
//传入的名称要注意,名称一样即为同一把锁
RLock lock = redissonClient.getLock("lock");
lock.lock(30,TimeUnit.SECONDS);
//执行具体的业务逻辑
}
注意传入的名称为同一个,即为同一把锁,所以这个锁的名称就涉及到锁的粒度,锁的粒度是越小越好的
此外,Reddssion还提供了公平锁,红锁,读写锁,信号量等等,这里不再说明,可以参照文档.
官方文档:Redisson
三.分布式锁实现原理
这里以不指定过期时间,使用看门狗进行续期的情况进行分析.
加锁过程
这里会默认传一个-1的过期时间,以便后续进行判断,是-1的话则使用看门狗续期
然后进行尝试加锁
这里采用了异步加锁的方式,当加锁成功后,回调执行看门狗逻辑的方法.
这里我们先看它的异步加锁方法:
其实最主要的就是执行了一段lua脚本,保证了多个操作的原子性
根据这个lua脚本,也能看出这个锁是可重入的,如果当前key存在的话,就将value进行+1.
看门狗续期过程
这里我们再回到使用看门狗进行续期的方法
在整个加锁过程中,这个看门狗的实现还是很细节的,这是一个比较复杂的操作.
因为这里有一个问题,我们知道,如果想对一个key进行续期,我们最简单的可以指定一个定时任务,重复的去执行这个续期逻辑.但是在一个项目中,可能会有很多不同的分布式锁, 那每一个锁都单独的一个定时任务吗?那很多锁的情况下岂不是要很多的定时任务?这样的话对项目影响岂不是很大?
那Reddssion是怎样处理的呢?我们一起看一下
这里往一个东西里面添加了定时任务,这个定时任务具体要做的就是使用lua脚本对key进行续期,续期成功后,递归执行这个方法,为什么要递归呢?这个定时任务谁控制去执行的呢?
我们点开 commandExecutor.getConnectionManager().newTimeout()方法,看看它做了什么?
看到这里,可能有的人就知道了,这里其实运用了HashedWheelTimer类,它是netty内部的一个工具类,主要运用了时间轮算法,内部有且仅有一个worker线程,可以动态的添加延时任务,但是每个任务只会执行一次,所以上面会递归的去添加任务.
而因为其内部只有一个worker线程,所以并不会对项目影响很大,有小伙伴不了解这个HashedWheelTimer,可以看下这个文章时间轮算法HashedWheelTimer
看完就会理解看门狗为什么要这样实现了.
这里要注意:
如果你不主动释放锁的话,redisson中的看门狗默认会一直帮你续期,即使程序出现异常或者线程中断,除非整个项目停止,这个时候看门狗也停止了,也就不会再续期了.所以一定要记得释放锁.
今天的分享就到这里了,有问题可以在评论区留言,均会及时回复呀.
我是bling,未来不会太差,只要我们不要太懒就行, 咱们下期见.