赞
踩
Redisson是一个在Redis的基础上实现的java驻内存数据网格,就是提供了一系列的分布式的java对象
官方地址:https://redisson.org
第一步:引入依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.6</version>
</dependency>
第二步:配置Redisson客户端:在配置文件中进行配置
这里通过配置类,完成对Redis的基本配置,在调用Redisson的创建方法根据这个配置类,创建出对应的客户端操作对象RedissonClient
@Configuration
public class RedisConfig {
public RedissonClient redissonClient(){
//配置类
Config config=new Config();
//添加redis地址,这里添加单点的地址,也可以使用config.useClusterServers()添加集群地址
config.useSingleServer().setAddress("redis://192.168.75.135.101:6379").setPassword("520521");
//创建客户端
return Redisson.create(config);
}
}
如何使用Redisson提供的分布式锁
@Resource private RedissonClient redissonClient; @Test void testRedisson() throws InterruptedException { //获取锁(可重入),指定锁的名称 RLock nihao = redissonClient.getLock("nihao"); //尝试获取锁,参数分别是,最大等待时间,锁自动释放时间,时间单位 boolean b = nihao.tryLock(1, 10, TimeUnit.SECONDS); //判断锁释放获取成功 if(b){ try{ System.out.println("执行业务"); }finally { //释放锁 nihao.unlock(); } } }
原理就是在存放value的时候通过计数器机制进行重复访问,当同一个线程在此访问这个锁的时候会进行判断,是不是自己同一个线程,是的话计数器加1,同理释放锁的时候就是将该计数器的数字减1
基本流程:
要实现上述操作功能需要用到Lua脚本
local key = KEYS[1];-- 锁的key local threadId = ARGV[1];-- 线程唯一标识 local releaseTime=ARGV[2];--锁的自动释放时间 -- 判断当前锁是否还是被自己持有 if(redis.call('HEXISTs",key,threadId)==0)then return nil;--如果已经不是自己,则直接返回 end; --是自己的锁,则重入次数- 1local count =redis.call('HINCRBY",key,threadId,-1); --判断是否重入次数是否已经为0 if(count>0)then --大于0说明不能释放锁,重置有效期然后返回 redis.call('EXPIRE",key, releaseTime); return nil; --等于0说明可以释放锁,直接删除 else redis.call('DEL',key); return nil; end ;
这是可复用锁的底层原理
在Redisson的操作类中已经实现了可重复锁的相关实现,在获取锁的同时会自动进行重复锁判断
Redisson底层通过使用Redis的watch机制和Lua脚本来实现解决超时释放锁的问题。当一个线程在获取锁时,Redisson会将锁的持有者信息保存到Redis中,并启动一个定时任务来监控锁的有效期。当锁的有效期超时时,定时任务会使用Lua脚本来检查锁是否还是当前线程持有,如果是则延长锁的有效期,如果不是则释放锁。这种机制可以确保在锁超时释放的情况下,不会出现并发访问问题。通过这种方式,Redisson能够在底层实现有效地解决超时释放的问题。
前面讲到在进行判断的时候如果没有拿到锁就会返回失败,Redis中提供了重试机制,设置一个最大等待时间,期间进行重复获取锁的操作
在当下的场景中都是多台Redis服务器进行主从服务器,假定这时有一个线程访问中Redis服务器,成功获取锁,就在这时,主服务器与从服务器同步数据的时候主服务器出现故障,这时Redis哨兵会从从服务器中选出一个来当主服务器,这是锁信息并未同步,就在这时其他线程也能够得到锁进行操作,就会出现问题
解决方案:
在Redisson中提供联锁方案,就是需要同时给多个Redis节点所送锁的信息,这时后就要判断,如果有一个失败,那么所有的节点获取锁都会失败
Rlock lock1=redissonClient.getLock("order");
Rlock lock2=redissonClient2.getLock("order");
Rlock lock3=redissonClient3.getLock("order");
//创建联锁
redissonClient.getMultiLock(lock1,lock2,lock3);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。