当前位置:首页 > 新闻资讯 > FPGA之家动态 >

redisson-分布式锁 快速入门

时间:2024-07-28      来源:网络搜集 关于我们 0

使用分布式锁优化可以实现双写一致性,今天就来介绍一种具体实现方式redisson-分布式锁

原理

原理图如下:

主要分析如下:

何时加锁?

线程去获取锁,获取成功: 执行lua脚本,保存数据到redis数据库。 线程去获取锁,获取失败: 一直通过while循环尝试获取锁,获取成功后,执行lua脚本,保存数据到redis

什么是WatchDog自动延期机制?

在一个分布式环境下,假如一个线程获得锁后,突然服务器宕机了,那么这个时候在一定时间后这个锁会自动释放,你也可以设置锁的有效时间(不设置默认30秒),这样的目的主要是防止死锁的发生 线程A业务还没有执行完,时间就过了,线程A 还想持有锁的话,就会启动一个watch dog后台线程,不断的延长锁key的生存时间

lua脚本

主要是如果你的业务逻辑复杂的话,通过封装在lua脚本中发送给redis,而且redis是单线程的,这样就保证这段复杂业务逻辑执行的原子性 基本使用

RLock是继承Lock锁,所以他有Lock锁的所有特性,比如lock、unlock、trylock等特性,同时它还有很多新特性:强制锁释放,带有效期的锁

public interface RLock { //----------------------Lock接口方法----------------------- /** * 加锁 锁的有效期默认30秒 */ void lock; /** * 加锁 可以手动设置锁的有效时间 * * @param leaseTime 锁有效时间 * @param unit 时间单位 小时、分、秒、毫秒等 */ void lock(long leaseTime, TimeUnit unit); /** * tryLock方法是有返回值的,用来尝试获取锁, * 如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false . */ boolean tryLock; /** * tryLock(long time, TimeUnit unit)方法和tryLock方法是类似的, * 只不过区别在于这个方法在拿不到锁时会等待一定的时间, * 在时间期限之内如果还拿不到锁,就返回false。如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。 * * @param time 等待时间 * @param unit 时间单位 小时、分、秒、毫秒等 */ boolean tryLock(long time, TimeUnit unit) throws InterruptedException; /** * 比上面多一个参数,多添加一个锁的有效时间 * * @param waitTime 等待时间 * @param leaseTime 锁有效时间 * @param unit 时间单位 小时、分、秒、毫秒等 */ boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException; /** * 解锁 */ void unlock; } lock方法

**lock**:此方法为加锁,但是锁的有效期采用默认30秒,如果主线程未释放,且当前锁未调用unlock方法,则进入到watchDog机制,如果主线程未释放,且当前锁调用unlock方法,则直接释放锁

@GetMapping("/lock") public String lock { //获得分布式锁对象,注意,此时还没有加锁成功 RLock lock = redissonClient.getLock("mylock"); try { //加锁:锁的有效期默认30秒 lock.lock; long timeToLive=lock.remainTimeToLive; log.info("线程:{},获得锁,锁存活时间:{}S",Thread.currentThread.getName,timeToLive/1000); //休眠一下 Thread.sleep(2000); }catch (Exception ex){ System.out.println("出现异常!!!"); }finally { //如果主线程未释放,且当前锁未调用unlock方法,则进入到watchDog机制 //如果主线程未释放,且当前锁调用unlock方法,则直接释放锁 log.info("线程:{},释放锁",Thread.currentThread.getName); } return "OK"; }

注意:加锁:锁的有效期默认30秒

lock(long leaseTime, TimeUnit unit):可以手动设置锁的有效时间,如果主线程未释放,且当前锁未调用unlock方法,则锁到期后会自动释放,如果主线程未释放,且当前锁调用unlock方法,则直接释放锁

@GetMapping("/lockLaseTime") public String lockLaseTime { //获得分布式锁对象,注意,此时还没有加锁成功 RLock lock = redissonClient.getLock("lockLaseTime"); try { //这里可以手动设置锁的有效时间,锁到期后会自动释放的 lock.lock(10,TimeUnit.SECONDS); long timeToLive=lock.remainTimeToLive; log.info("线程:{},获得锁,锁存活时间:{}S",Thread.currentThread.getName,timeToLive/1000); //休眠一下 Thread.sleep(2000); }catch (Exception ex){ System.out.println("出现异常!!!"); }finally { //如果主线程未释放,且当前锁未调用unlock方法,则进入到watchDog机制 //如果主线程未释放,且当前锁调用unlock方法,则直接释放锁 log.info("线程:{},释放锁",Thread.currentThread.getName); } return "OK"; } tryLock方法

tryLock:用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,如果主线程未释放,且当前锁未调用unlock方法,则进入到watchDog机制,如果主线程未释放,且当前锁调用unlock方法,则直接释放锁

@GetMapping("/tryLock") public String tryLock { //获得分布式锁对象,注意,此时还没有加锁成功 RLock lock = redissonClient.getLock("tryLock"); try { //如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false . boolean flag=lock.tryLock; if(flag){ long timeToLive=lock.remainTimeToLive; log.info("线程:{},获得锁,锁存活时间:{}S,加锁状态:{}",Thread.currentThread.getName,timeToLive/1000,flag); //休眠一下 Thread.sleep(2000); } }catch (Exception ex){ System.out.println("出现异常!!!"); }finally { //如果主线程未释放,且当前锁未调用unlock方法,则进入到watchDog机制 //如果主线程未释放,且当前锁调用unlock方法,则直接释放锁 log.info("线程:{},释放锁",Thread.currentThread.getName); } return "OK"; }

tryLock(long time, TimeUnit unit):tryLock(long time, TimeUnit unit)方法和tryLock方法是类似的,只不过区别在于这个方法在拿不到锁时会等待一定的时间, 在时间期限之内如果还拿不到锁,就返回false。如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true,如果主线程未释放,且当前锁未调用unlock方法,则进入到watchDog机制如果主线程未释放,且当前锁调用unlock方法,则直接释放锁

@GetMapping("/tryLockWaitTime") public String tryLockWaitTime { //获得分布式锁对象,注意,此时还没有加锁成功 RLock lock = redissonClient.getLock("tryLockWaitTime"); try { //只不过区别在于这个方法在拿不到锁时会等待一定的时间, //在时间期限之内如果还拿不到锁,就返回false。如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。 boolean flag=lock.tryLock(6, TimeUnit.SECONDS); if(flag){ long timeToLive=lock.remainTimeToLive; log.info("线程:{},获得锁,锁存活时间:{}S,加锁状态:{}",Thread.currentThread.getName,timeToLive/1000,flag); //休眠一下 Thread.sleep(2000); } }catch (Exception ex){ System.out.println("出现异常!!!"); }finally { //如果主线程未释放,且当前锁未调用unlock方法,则进入到watchDog机制 //如果主线程未释放,且当前锁调用unlock方法,则直接释放锁 log.info("线程:{},释放锁",Thread.currentThread.getName); } return "OK"; }

注意:tryLock(long time, TimeUnit unit),这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true

SpringBoot项目依赖 <!--redis--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>2.4.0</version> </dependency> <!--使用redisson作为分布式锁--> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.16.8</version> </dependency> 配置类和配置文件 返回搜狐,查看更多

配置文件 spring: redis: # Redis数据库索引(默认为0) database: 0 # Redis服务器地址 host: 127.0.0.1 # Redis服务器连接端口 port: 6379 # Redis服务器链接密码(默认为空) password: jedis: pool: # 连接池最大链接数(负值表示没有限制) max-active: 20 # 连接池最大阻塞等待时间(负值表示没有限制) max-wait: -1 # 链接池中最大空闲链接 max-idle: 10 # 连接池中最小空闲链接 min-idle: 0 # 链接超市时间(毫秒) timeout: 1000 server: port: 8899 配置类 @Configuration public class RedissonConfig { @Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") private String port; @Bean public RedissonClient redissonClient{ Config config = new Config; config.useSingleServer.setAddress("redis://" + host + ":" + port); final RedissonClient client = Redisson.create(config); return client; } }

责任编辑:


注明:本内容来源网络,不用于商业使用,禁止转载,如有侵权,请来信到邮箱:429562386ⓐqq.com 或联系本站客服处理,感谢配合!

用户登陆

    未注册用户登录后会自动为您创建账号

提交留言