【Java】分布式锁Redis和Redisson
https://blog.csdn.net/weixin_44606481/article/details/134373900
https://www.bilibili.com/video/BV1nW421R7qJ
Redis锁机制一般是由 setnx 命令实现,set if not exists,语法setnx key value,将key设置值为value,如果key不存在会返回1,这种情况下等同 set 命令。 当key存在时,什么也不做会返回0,并且要使用 expire 设置一个锁的过期时间,避免应用程序异常导致锁一直没有释放(或者可以通过 try catch finally来释放锁)。
127.0.0.1:6379> setnx key1 1
(integer) 1
127.0.0.1:6379> setnx key1 1
(integer) 0
127.0.0.1:6379> expire key1 60
(integer) 1
@Override
public void testLock() {//从redis里面获取数据//1 获取当前锁 setnxBoolean ifAbsent = redisTemplate.opsForValue().setIfAbsent("lock", "lock");//2 如果获取到锁,从redis获取数据 数据+1 放回redis里面if(ifAbsent) {//获取锁成功,执行业务代码//1.先从redis中通过key num获取值 key提前手动设置 num 初始值:0String value = redisTemplate.opsForValue().get("num");//2.如果值为空则非法直接返回即可if (StringUtils.isBlank(value)) {return;}//3.对num值进行自增加一int num = Integer.parseInt(value);redisTemplate.opsForValue().set("num", String.valueOf(++num));//3 释放锁redisTemplate.delete("lock");} else {try {Thread.sleep(100);this.testLock();} catch (InterruptedException e) {e.printStackTrace();}}
}
LUA脚本保证原子性
不是原子性可能导致的问题:

把index2的分布式锁给删掉了
给分布式锁加上uuid,可以防止删除不是自己的锁,锁误删
//lua脚本保证原子性
@Override
public void testLock() {//从redis里面获取数据String uuid = UUID.randomUUID().toString();//1 获取当前锁 setnx + 设置过期时间// Boolean ifAbsent = redisTemplate.opsForValue().setIfAbsent("lock", "lock");Boolean ifAbsent =redisTemplate.opsForValue().setIfAbsent("lock", uuid,3, TimeUnit.SECONDS);//2 如果获取到锁,从redis获取数据 数据+1 放回redis里面if(ifAbsent) {//获取锁成功,执行业务代码//1.先从redis中通过key num获取值 key提前手动设置 num 初始值:0String value = redisTemplate.opsForValue().get("num");//2.如果值为空则非法直接返回即可if (StringUtils.isBlank(value)) {return;}//3.对num值进行自增加一int num = Integer.parseInt(value);redisTemplate.opsForValue().set("num", String.valueOf(++num));//出现异常//3 释放锁 lua脚本实现DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();//lua脚本String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +"then\n" +" return redis.call(\"del\",KEYS[1])\n" +"else\n" +" return 0\n" +"end";redisScript.setScriptText(script);//设置返回结果redisScript.setResultType(Long.class);redisTemplate.execute(redisScript, Arrays.asList("lock"),uuid);} else {try {Thread.sleep(100);this.testLock();} catch (InterruptedException e) {e.printStackTrace();}}
}
锁
为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:
第一个:互斥性,在任何时刻,只有一个客户端能持有锁。
第二个:不会发生死锁,即使有一个客户端在获取锁操作时候崩溃了,也能保证其他客户端能获取到锁。
第三个:解铃还须系铃人,解锁加锁必须同一个客户端操作。 (uuid来保证)
第四个:加锁和解锁必须具备原子性
Redisson
- Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务。
- Redisson的宗旨是:促进使用者对Redis的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上。
Redisson常见作用
-
分布式对象:分布式对象简单来说就是存储在Redis中的Java对象。不同的Java应用程序或服务就能够共享和访问这些对象,实现数据共享和数据同步。
-
分布式集合:简单来说就是将集合放在Redis中,并且可以多个客户端对集合进行操作。Redisson支持常见的分布式数据结构,如List、Set、Map、Queue等,使得多个Java应用程序可以并发地访问和修改这些集合。
-
分布式锁:通过Redisson,你可以轻松地实现分布式锁,确保在分布式环境中的并发操作的正确性和一致性。
-
缓存:通过Redisson能够轻松的基于redis实现项目中的缓存
-
常见算法的分布式实现:Redisson提供了一些常用算法的分布式实现,如分布式信号量、分布式位图、分布式计数器等。
导入依赖
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId>
</dependency>
创建Redisson配置类
@Data
@Configuration
@ConfigurationProperties(prefix = "spring.data.redis")
public class RedissonConfig {private String host;private String password;private String port;private int timeout = 3000;private static String ADDRESS_PREFIX = "redis://";/*** 自动装配**/@BeanRedissonClient redissonSingle() {Config config = new Config();if(!StringUtils.hasText(host)){throw new RuntimeException("host is empty");}SingleServerConfig serverConfig = config.useSingleServer().setAddress(ADDRESS_PREFIX + this.host + ":" + port).setTimeout(this.timeout);if(StringUtils.hasText(this.password)) {serverConfig.setPassword(this.password);}return Redisson.create(config);}
}
在业务方法编写加锁和解锁
@Autowired
private RedissonClient redissonClient;//Redisson实现
@Override
public void testLock() {//1 通过redisson创建锁对象RLock lock = redissonClient.getLock("lock1");//2 尝试获取锁//(1) 阻塞一直等待直到获取到,获取锁之后,默认过期时间30slock.lock();//(2) 获取到锁,锁过期时间10s// lock.lock(10,TimeUnit.SECONDS);//(3) 第一个参数获取锁等待时间// 第二个参数获取到锁,锁过期时间// try {// // true// boolean tryLock = lock.tryLock(30, 10, TimeUnit.SECONDS);// } catch (InterruptedException e) {// throw new RuntimeException(e);// }//3 编写业务代码//1.先从redis中通过key num获取值 key提前手动设置 num 初始值:0String value = redisTemplate.opsForValue().get("num");//2.如果值为空则非法直接返回即可if (StringUtils.isBlank(value)) {return;}//3.对num值进行自增加一int num = Integer.parseInt(value);redisTemplate.opsForValue().set("num", String.valueOf(++num));//4 释放锁lock.unlock();
}
Redisson原理
1、如果我们指定了锁的超时时间,就发送给Redis执行脚本,进行占锁,默认超时就是我们制定的时间,不会自动续期;
2、如果我们未指定锁的超时时间,就使用lockWatchdogTimeout = 30 * 1000【看门狗默认时间】
看门狗的作用:为了保证业务操作 在 有锁的状态下进行。
只要线程一加锁成功,就会启动一个watch dog看门狗,它是一个后台线程,会每隔10秒检查一下,如果线程一还持有锁,那么就会不断的延长锁key的生存时间。因此,Redisson就是使用Redisson解决了锁过期释放,业务没执行完问题。
基于Redis的Redisson分布式可重入锁RLock Java对象实现了java.util.concurrent.locks.Lock接口。
如果负责储存这个分布式锁的Redisson节点宕机以后,而且这个锁正好处于锁住的状态时,这个锁会出现锁死的状态。为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。默认情况下,看门狗的检查锁的超时时间是30秒钟,也可以通过修改Config.lockWatchdogTimeout来另行指定。
另外Redisson还通过加锁的方法提供了leaseTime的参数来指定加锁的时间。超过这个时间后锁便自动解开了。
相关文章:
【Java】分布式锁Redis和Redisson
https://blog.csdn.net/weixin_44606481/article/details/134373900 https://www.bilibili.com/video/BV1nW421R7qJ Redis锁机制一般是由 setnx 命令实现,set if not exists,语法setnx key value,将key设置值为value,如果key不存在…...
Python的imutils库详细介绍
imutils 是一个专为简化OpenCV(计算机视觉库)常见操作而设计的Python工具库,提供了一系列便捷函数,使图像和视频处理更加高效和简洁。以下是对其功能、安装及用法的详细介绍: 1. 安装方法 通过pip安装: p…...
蓝桥杯 Java B 组之简单动态规划(爬楼梯、斐波那契数列)
Day 6:简单动态规划(爬楼梯、斐波那契数列) 动态规划(Dynamic Programming,简称 DP)是计算机科学中的一种算法设计思想,用来解决最优解问题,它的核心思想是将大问题分解为小问题&am…...
Hive增量迁移方案与实操PB级
客户一共1PB数据,每天新增10T,有些表只保留3天。 需要客户提供: a.tbl_size(大小GB) a.last_mtime(最新更新时间) a.tbl_ttl(保留时间) b.last_part_dt(分区值) b.last_part_size(最新分区大小) t_day(表更新规律,t几) 因为目前…...
【练习】【双指针】力扣热题100 283. 移动零
题目 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] 示例 2: 输入: nums [0] 输出…...
Python 依赖管理的革新——Poetry 深度解析
引言 在 Python 生态中,依赖管理一直是开发者关注的重要话题。从最初的 pip 和 virtualenv,到后来的 pipenv,Python 依赖管理工具不断进化。而近年来,Poetry 作为一款集成包管理和虚拟环境管理的新兴工具,逐渐获得了广…...
从零开始学Python爬虫:(二)使用基本库urllib(下)
一、异常处理 关于某些情况下,可能会出现异常,如果不处理它们,会发生很多错误。 而urllib库提供了error模块来处理这些异常,该模块包括以下功能: (1)URLError 该类含有一个属性reason&#x…...
电商分布式场景中如何保证数据库与缓存的一致性?实战方案与Java代码详解
文章目录 一、缓存一致性问题的本质写后读不一致:更新数据库后,缓存未及时失效并发读写竞争:多个线程同时修改同一数据缓存与数据库事务不同步:部分成功导致数据错乱 二、5大核心解决方案与代码实现方案1:延迟双删策略…...
kamailio中Core Cookbook 核心配置手册
Core Cookbook 核心配置手册 版本: Kamailio SIP 服务器 v6.0.x (稳定版) 概述 本教程收集了 Kamailio 核心导出到配置文件的功能和参数。 注意: 本页参数未按字母顺序排列。 结构 kamailio.cfg 的结构可分为三部分: 全局参数模块设置路由块 建议按此顺序排列以保持清晰…...
【嵌入式Linux应用开发基础】read函数与write函数
目录 一、read 函数 1.1. 函数原型 1.2. 参数说明 1.3. 返回值 1.4. 示例代码 二、write 函数 2.1. 函数原型 2.2. 参数说明 2.3. 返回值 2.4. 示例代码 三、关键注意事项 3.1 部分读写 3.2 错误处理 3.3 阻塞与非阻塞模式 3.4 数据持久化 3.5 线程安全 四、嵌…...
一、OpenSM 架构部署及原理详解
目录 一、OpenSM 架构与核心功能 1. InfiniBand 子网管理器(SM)的作用 2. OpenSM 的架构 二、OpenSM 部署步骤(以 Linux 为例) 1. 安装依赖与软件包 2. 配置文件 3. 启动 OpenSM 服务 4. 验证部署 5. 高可用性配置(可选) 三、OpenSM 工作原理详解 1. 拓扑发现(…...
2526考研资料分享 百度网盘
通过网盘分享的文件:01、2026【考研数学】 链接:https://pan.baidu.com/s/1PwMzp_yCYqjBqa7492mP3w?pwd98wg 提取码:98wg--来自百度网盘超级会员v3的分享 通过网盘分享的文件:01、2026【考研政治】 链接:https://pan.baidu.com/s/1PwMzp_yCYqjBqa7492…...
15.1 Process(进程)类
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 通常开发时想要获得进程是比较困难的事,必须要调用CreateToolhelpSnapshot、ProcessFirst、ProcessNext等API或者诸如 Zw…...
事件传递和监控
今天介绍一下UIApplication的函数 - (BOOL)sendAction:to:from:forEvent: - (BOOL)sendAction:to:from:forEvent: 是 UIApplication 类中的一个方法,主要用于发送事件响应链中的动作(action)。它允许应用程序从一个特定的发送者(…...
CentOS 7 企业级Redis 7部署指南
CentOS 7 企业级Redis 7部署指南 目录导航 一、环境准备 1.1 依赖管理 二、离线安装 2.1 源码编译安装2.2 目录结构规范 三、生产配置 3.1 主配置文件3.2 配置生成脚本 四、系统集成 4.1 Systemd服务文件4.2 服务管理命令 五、安全加固 5.1 网络安全配置5.2 审计配置 六、性能…...
Python创建Excel的方式——提供4中方式可供参考
目录 专栏导读库的安装代码1——pandas代码2——openpyxl代码3——xlsxwriter代码4——xlwings总结 专栏导读 🌸 欢迎来到Python办公自动化专栏—Python处理办公问题,解放您的双手 🏳️🌈 博客主页:请点击——>…...
消息中间件深度剖析:以 RabbitMQ 和 Kafka 为核心
在现代分布式系统和微服务架构的构建中,消息中间件作为一个不可或缺的组件,承担着系统间解耦、异步处理、流量削峰、数据传输等重要职能。尤其是在面临大规模并发、高可用性和可扩展性需求时,如何选择合适的消息中间件成为了开发者和架构师们…...
回文数:简单问题中的多种优化思路
回文数:简单问题中的多种优化思路 引言 回文数(Palindrome Number)是一个有趣的问题,在算法竞赛、面试、甚至一些实际应用场景中都会遇到。最直观的方式是将数字转换成字符串,然后反转比较。但仅仅满足“能解”是不够…...
大语言模型简史:从Transformer(2017)到DeepSeek-R1(2025)的进化之路
2025年初,中国推出了具有开创性且高性价比的「大型语言模型」(Large Language Model — LLM)DeepSeek-R1,引发了AI的巨大变革。本文回顾了LLM的发展历程,起点是2017年革命性的Transformer架构,该架构通过「…...
java八股文-spring
目录 1. spring基础 1.1 什么是Spring? 1.2 Spring有哪些优点? 1.3 Spring主要模块 1.4 Spring常用注解 1.5 Spring中Bean的作用域 1.6 Spring自动装配的方式 1.7 SpringBean的生命周期 1.8 多级缓存 1.9 循环依赖? 1 .8.1 原因 1.8…...
机器学习--实现多元线性回归
机器学习—实现多元线性回归 本节顺延机器学习--线性回归中的内容,进一步讨论多元函数的回归问题 y ′ h ( x ) w ⊤ ∙ x b y^{\prime}h(x)w^\top\bullet xb y′h(x)w⊤∙xb 其中, w T ⋅ x 就是 W 1 X 1 w 2 X 2 w 3 X 3 ⋯ w N X N \text{其中,}w^\math…...
vue3响应式丢失解决办法(三)
vue3的响应式的理解,与普通对象的区别(一) vue3 分析总结响应式丢失问题原因(二) 经过前面2篇文章,知道了响应式为什么丢失了,但是还是碰到了丢失情况,并且通过之前的内容还不能解…...
NLP 八股 DAY1:BERT
BERT全称:Pre-training of deep bidirectional transformers for language understanding,即深度双向Transformer。 模型训练时的两个任务是预测句⼦中被掩盖的词以及判断输⼊的两个句⼦是不是上下句。在预训练 好的BERT模型后⾯根据特定任务加上相应的⽹…...
蓝桥与力扣刷题(230 二叉搜索树中第k小的元素)
题目:给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 小的元素(从 1 开始计数)。 示例 1: 输入:root [3,1,4,null,2], k 1 输出:1示例 2ÿ…...
半遮挡检测算法 Detecting Binocular Half-Occlusions
【1. 背景】: 本文分析【Detecting Binocular Half-Occlusions:Empirical Comparisons of Five Approaches】Geoffrey Egnal和Richard P. Wildes于2002年发表在IEEE Transactions on Pattern Analysis and Machine Intelligence上,这是1篇中…...
PHP培训机构教务管理系统小程序
🔑 培训机构教务管理系统——智慧教育,高效管理新典范 🚀 这款教务管理系统,是基于前沿的ThinkPHP框架与Uniapp技术深度融合,匠心打造的培训机构管理神器。它犹如一把开启高效运营与精细管理的金钥匙,专为…...
《LeetCode 763. 划分字母区间 | 高效分割字符串》
内容: 问题描述: 给定一个字符串 S,将字符串分割成若干个子串,使得每个子串中的字符都不重复,并且返回每个子串的长度。 解题思路: 找到每个字符最后一次出现的位置:我们首先遍历一遍字符串&a…...
无人机不等同轴旋翼架构设计应用探究
“结果显示,对于不等组合,用户应将较小的螺旋桨置于上游以提高能效,但若追求最大推力,则两个相等的螺旋桨更为理想。” 在近期的研究《不等同轴旋翼性能特性探究》中,Max Miles和Stephen D. Prior博士深入探讨了不同螺…...
什么是 大语言模型中Kernel优化
什么是 大语言模型中Kernel优化 目录 什么是 大语言模型中Kernel优化Kernel优化操作系统内核优化深度学习计算内核优化手工优化原理举例Flash Attention,Faster TransformerKernel优化 大语言模型存在访存密集操作(如注意力机制、LayerNorm等),这些操作使得GPU计算性能无法…...
DeepSeek与ChatGPT:AI语言模型的全面对决
DeepSeek与ChatGPT:AI语言模型的全面对决 引言:AI 语言模型的时代浪潮一、认识 DeepSeek 与 ChatGPT(一)DeepSeek:国产新星的崛起(二)ChatGPT:AI 界的开拓者 二、DeepSeek 与 ChatGP…...
