【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的参数来指定加锁的时间。超过这个时间后锁便自动解开了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/19265.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c++TinML转html

cTinML转html 前言解析解释转译html类定义开头html 结果这是最终效果&#xff08;部分&#xff09;&#xff1a; ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6cf6c3e3c821446a84ae542bcc2652d4.png) 前言 在python.tkinter设计标记语言(转译2-html)中提到了将Ti…

2.2 反向传播:神经网络如何“学习“?

一、神经网络就像小学生 想象一个刚学算术的小学生&#xff0c;老师每天布置练习题&#xff0c;学生根据例题尝试解题&#xff0c;老师批改后指出错误。神经网络的学习过程与此相似&#xff1a; 输入层&#xff1a;相当于练习题&#xff08;如数字图片&#xff09;输出层&…

QEMU 通过网络实现共享文件

系列文章目录 Linux内核学习 Linux 知识&#xff08;1&#xff09; Linux 知识&#xff08;2&#xff09; WSL Ubuntu QEMU 虚拟机 Linux 调试视频 PCIe 与 USB 的补充知识 vscode 使用说明 树莓派 4B 指南 设备驱动畅想 Linux内核子系统 Linux 文件系统挂载 QEMU 通过网络实现…

当时只道是寻常

晴&#xff0c;2025年2月16日 卸载了油管、脸书和 X 手机 app &#xff0c;太浪费我时间&#xff0c;以后再去经营吧。 教学技能大赛材料需要在明天之内搞定——《教学实施方案》。感觉玄&#xff0c;同部门有经验的老师说至少花一周时间。 只能明天早点继续接着弄&#xff…

Hive之分区表

Hive之分区表 文章目录 Hive之分区表写在前面分区表分区表基本操作引入分区表创建分区表语法加载数据到分区表中查询分区表中数据增加分区删除分区查看分区表有多少分区查看分区表结构 二级分区正常的加载数据分区表和数据产生关联 动态分区开启动态分区参数设置案例实操 写在前…

【线段树模板】

介绍 这段代码看起来是一个基于树结构的数据结构&#xff0c;可能是线段树或者其他类似的数据结构。主要包含了构建数据结构、查询和修改等基本操作的实现函数。以下是对每个函数的简要介绍&#xff1a; pushup(int u): 用于计算结点u的属性。build(int u, int l, int r): 用于…

DeepSeek辅助测试测试一 -- DeepSeek加MaxKB知识库本地部署

文章目录 前言任务拆解最终目标两种技术路径对比知识库检索增强&#xff08;RAG&#xff09; 大语言模型 构建知识库加本地部署DeepSeek目前的问题 前言 开工已经两周啦&#xff0c;开始慢慢的进入工作状态了&#xff0c;新的一年大家一起加油吧~ 任务拆解 最终目标 训练一…

Yuque-DL:一款强大的语雀资源下载工具

语雀是一款常用的文档管理工具&#xff0c;但官方未提供直接下载文档的功能。为此&#xff0c;可以使用第三方工具下载语雀文档。以下是使用步骤&#xff1a; 1. 安装工具 GitHub - gxr404/yuque-dl: yuque 语雀知识库下载 安装步骤&#xff1a; 确保已安装 Node.js&#xff…

【Java 面试 八股文】Spring Cloud 篇

Spring Cloud 篇 1. Spring Cloud 5大组件有哪些&#xff1f;2. 服务注册和发现是什么意思&#xff1f;Spring Cloud 如何实现服务注册发现&#xff1f;3. 我看你之前也用过nacos&#xff0c;你能说下nacos与eureka的区别&#xff1f;4. 你们项目负载均衡如何实现的&#xff1f…

国内外网络安全政策动态(2025年1月)

▶︎ 1.国家互联网信息办公室发布《个人信息出境个人信息保护认证办法&#xff08;征求意见稿&#xff09;》 1月3日&#xff0c;国家互联网信息办公室发布《个人信息出境个人信息保护认证办法&#xff08;征求意见稿&#xff09;》。根据《意见稿》&#xff0c;个人信息出境个…

图论入门算法:拓扑排序(C++)

上文中我们了解了图的遍历(DFS/BFS), 本节我们来学习拓扑排序. 在图论中, 拓扑排序(Topological Sorting)是对一个有向无环图(Directed Acyclic Graph, DAG)的所有顶点进行排序的一种算法, 使得如果存在一条从顶点 u 到顶点 v 的有向边 (u, v) , 那么在排序后的序列中, u 一定…

Anaconda +Jupyter Notebook安装(2025最新版)

Anaconda安装&#xff08;2025最新版&#xff09; Anaconda简介安装1&#xff1a;下载anaconda安装包2&#xff1a; 安装anaconda3&#xff1a;配置环境变量4&#xff1a;检查是否安装成功5&#xff1a;更改镜像源6&#xff1a;更新包7&#xff1a;检查 Jupyter Notebook一.Jup…

VS2022中.Net Api + Vue 从创建到发布到IIS

VS2022中.Net Api Vue 从创建到发布到IIS 前言一、先决条件二、创建项目三、运行项目四、增加API五、发布到IIS六、设置Vue的发布 前言 最近从VS2019 升级到了VS2022,终于可以使用官方的.Net Vue 组合了,但是使用过程中还是有很多问题,这里记录一下. 一、先决条件 Visual …

vue点击左边导航,右边出现页面步骤

vue点击左边导航&#xff0c;右边出现页面 步骤 一定要import不然会出错 index.js Course作为Homeview子路由 Homeview加入<Routerview> 点击跳转<RouterLink to> 父Homeview中有RouterView&#xff08;路由出口&#xff0c;跳转至相应路径&#xff09;和Router…

位运算,双指针,二分,排序算法

文章目录 位运算二进制中1的个数题解代码我们需要0题解代码 排序模版排序1题解代码模版排序2题解代码模版排序3题解代码 双指针最长连续不重复子序列题解代码 二分查找题解代码 位运算 1. bitset< 16 >将十进制数转为16位的二进制数 int x 25; cout << bitset<…

【力扣】102.二叉树的层序遍历

AC截图 题目 思路 维持一个队列&#xff0c;每次容纳一层的元素即可。 代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* Tre…

【HarmonyOS Next】图片选择方案

背景 封装一个选择图片和调用拍照相机的按钮&#xff0c;展示api13下选择图片和调用相机&#xff0c;可以使用不申请用户权限的方式&#xff0c;进行图片的选择和修改。但是&#xff0c;目前方案并未包含上传图片保存的功能&#xff0c;仅提供图片选择或者拍照后&#xff0c;图…

25年湖南省考报名流程保姆级教程

2025年湖南省考报名马上就要开始啦&#xff01; 有想要参加湖南省考的姐妹们&#xff0c;可以提前了解一下考试报名流程&#xff0c;熟悉考试报名照上传要求&#xff01; 一、考试时间安排 报名时间&#xff1a;2月17日9:00至2月25日 17:00 审核时间&#xff1a;2月17日9:0…

某大型业务系统技术栈介绍【应对面试】

微服务架构【图】 微服务架构【概念】 微服务架构&#xff0c;是一种架构模式&#xff0c;它提倡将单一应用程序划分成一组小的服务&#xff0c;服务之间互相协调、互相配合&#xff0c;为用户提供最终价值。在微服务架构中&#xff0c;服务与服务之间通信时&#xff0c;通常是…

STM32的DMA解释

一句话解释&#xff1a; DMA的特点就是无需CPU的参与就可以直接访问内存&#xff08;可以直接读取内存的数据&#xff0c;也可以直接传数据给内存&#xff09; 这个内存一般指的是片内SRAM、片内Flash 我举个例子&#xff1a; 有一个温度传感器&#xff0c;它以较高的频率&a…