
springboot下Redission实现redis分布式锁
发布日期:2021-05-08 20:43:23
浏览次数:22
分类:精选文章
本文共 3592 字,大约阅读时间需要 11 分钟。
直接使用redisson实现分布式锁
加锁原理

- 线程一去获取锁,获取成功,执行lua脚本,保存数据到redis数据库。线程二去获取锁,获取失败, 一直通过while循环尝试获取锁。获取成功后,执行lua脚本,保存数据到redis数据库。
- Watch dog所起到的作用就是当锁的有效时间要到了当业务逻辑却还没有执行完成时,延长锁的有效时间。 注:正常这个看门狗线程是不启动的,还有就是这个看门狗启动后对整体性能也会有一定影响,所以不建议开启看门狗。
- 将复杂的业务逻辑封装在lua脚本中发送给redis,且redis是原子性的,这样就保证了这段逻辑的原子性。
Redisson可以实现可重入加锁机制
- 线程二在已经持有锁的情况下再进去,就不需要改线程ID,只需改一下value值即可。这里有点像偏向锁的加锁过程:当检查锁标志位成功的时候,会通过CAS的操作,将Mark Word中的线程ID改为自己的线程ID,并将偏向锁位置为1。如果下一次还是线程二进入同步区,就不需要执行这一步
在Redis哨兵模式下,当线程一给master节点写入redission锁,会异步复制给slave节点。如果此时master节点发生故障宕机,就会发生主备切换,slave节点变成了master节点。此时线程二也可以给新的master节点写入redission锁。这样就会产生在同一时刻能有多个客户端对同一个分布式锁加锁,这样就可能会导致脏数据的产生。
上一波依赖
org.redisson redisson 3.8.2
package com.fchan.redission.util;import org.redisson.Redisson;import org.redisson.api.RedissonClient;import org.redisson.config.Config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class RedissionUtil { @Bean public RedissonClient redissionClient() { Config config = new Config(); //单机模式 config.useSingleServer() .setAddress("redis://192.168.56.101:36379") .setPassword("111") .setDatabase(1); //集群模式 /*config.useClusterServers() .addNodeAddress("redis://192.168.56.101:36379") .addNodeAddress("redis://192.168.56.102:36379") .addNodeAddress("redis://192.168.56.103:36379") .setPassword("1111111") .setScanInterval(5000);*/ //哨兵模式 /*config.useSentinelServers().addSentinelAddress("redis://ip1:port1", "redis://ip2:port2", "redis://ip3:port3") .setMasterName("mymaster") .setPassword("password") .setDatabase(0);*/ RedissonClient redissonClient = Redisson.create(config); return redissonClient; }}
使用redisson的并发锁
package com.fchan.redission.controller;import lombok.extern.slf4j.Slf4j;import org.redisson.api.RLock;import org.redisson.api.RedissonClient;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import java.util.concurrent.TimeUnit;@RestController@RequestMapping("api/redisson")@Slf4jpublic class RedissonController { @Autowired private RedissonClient redissonClient; public static Integer count = 0; @PostMapping("test") public String testRedisson(){ RLock lock = redissonClient.getLock("myLock"); try { log.info("开始加锁"); count ++; log.info("count ++ 之后的值 {}",count); //lock.lock(); //简单的获取锁 // 获取锁最多等待500ms,10s后key过期自动释放锁 boolean getLock = lock.tryLock(500,10000, TimeUnit.MILLISECONDS); if (!getLock) { log.info("当前线程:[{}]没有获得锁", Thread.currentThread().getName()); return "failed"; } } catch (Exception e) { e.printStackTrace(); } finally { //lock.isHeldByCurrentThread() 判断当前线程是否持有锁 if(null != lock && lock.isHeldByCurrentThread()){ lock.unlock(); } } return "success"; }}
锁过期时间的设置
- 这个问题的场景是,假设设置失效时间10秒,如果由于某些原因导致10秒还没执行完任务,这时候锁自动失效,导致其他线程也会拿到锁。
集群模式下主从切换导致的锁丢失
- 这个问题的场景 在Redis的master节点上拿到了锁; 但是这个加锁的key还没有同步到slave节点; master故障,发生故障转移,slave节点升级为master节点; 导致锁丢失。
发表评论
最新留言
路过,博主的博客真漂亮。。
[***.116.15.85]2025年04月13日 22时54分09秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
采坑 - 字符串的 "" 与 pd.isnull()
2021-05-09
无序列表 - 链表
2021-05-09
Matplotlib绘制漫威英雄战力图,带你飞起来!
2021-05-09
机器学习是什么
2021-05-09
《小王子》里一些后知后觉的道理
2021-05-09
《你当像鸟飞往你的山》总结
2021-05-09
《我是猫》总结
2021-05-09
《抗糖化书》总结
2021-05-09
apache虚拟主机配置
2021-05-09
PHP官方网站及PHP手册
2021-05-09
mcrypt加密以及解密过程
2021-05-09
go等待N个线程完成操作总结
2021-05-09
ReactJs入门教程-精华版
2021-05-09
Python 之网络式编程
2021-05-09
MySql5.5安装步骤及MySql_Front视图配置
2021-05-09
Java内存模型(JMM)
2021-05-09
AQS相关
2021-05-09
WCF学习之旅—第三个示例之一(二十七)
2021-05-09