RedisTemplate实现锁超时时间延长(模仿Redisson看门狗机制)

业务场景:

在上一篇-Java业务功能并发问题处理的最后,我们用RedisTemplate实现了一个分布式锁,但是后面又有用户反馈同个单据出现了重复操作,让我们回忆下上次的加锁代码:
分布式锁请求锁逻辑


问题描述:

原因出现在我们锁住的那段代码执行了太久,超过预设的过期时长。在A线程还在执行中时,Redis中作为锁的key已经过期了,当B线程进入时判断已经没有锁了,因此允许执行。

解决方案分析:

由于我们不知道业务需要执行多久,需要一个机制在过期前检查是否线程还在运行中(为什么必须是过期前?因为过期了我们就无法知道线程是超时导致的解锁还是线程主动的解锁。),如果线程仍在运行,则将过期时间延长。下面绘制一个流程图让大家更直观地了解整个流程,此处是模仿Redisson看门狗机制
仿造看门狗机制流程图

代码实现:

// ...省略循环等代码
isSuccessLock = redisTemplate.opsForValue().setIfAbsent(redisKey, Thread.currentThread().getName(), lockTime, TimeUnit.MILLISECONDS);
if (Boolean.TRUE.equals(isSuccessLock)) {// 新增的重置过期时间方法 在加锁成功后, 开启1个线程, 做redis看门狗机制renewExpiration(lockKey, Thread.currentThread().getName(), lockTime);return true;
}
// 省略for循环中的try...catch代码

renewExpiration刷新锁时间的方法实现

/*** lua脚本 更新锁时间, 如果已经获取不到值, 则不更新锁的过期时间*/
private static final String REDIS_RENEW_LOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] " +"then return redis.call('expire', KEYS[1], ARGV[2]) " +"else return 0 end";
/*** 刷新锁时间* @param lockKey   锁key* @param requestId 锁线程号,redis的value* @param lockTime  锁时长*/
public void renewExpiration(String lockKey, String requestId, long lockTime) {DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(REDIS_RENEW_LOCK_SCRIPT, Long.class);// 通过线程池创建异步线程taskExecutor.execute(() -> {while (true) {try {// 等待锁时长的1/3后刷新锁的过期时间Thread.sleep(lockTime / 3 * 1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();break;}// 当前template只能传字符串, 将时间转为字符串传入String timeStr = String.valueOf(lockTime);// 延长过期时间原子操作Long execute = redisTemplate.execute(redisScript, new ArrayList<>(Collections.singleton(lockKey)), requestId, timeStr);if (execute == null || execute == 0) {break;}}});
}

总结:

其实后面才了解到Redis的分布式锁直接引入Redisson就万事大吉了,建议大家直接通过Redisson去做Redis的分布式锁,省时省力,方便完善。此处自己写其实也是为了更深入了解分布式锁的实现,而且一开始觉得就一个类解决的事情,引入多余的一个工具包会不会有点多余,结果做到后面才发现也有一些坑是自己没考虑周到的。等我后面有时间一定直接引入Redisson

参考链接:

redission的看门狗机制及应用

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

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

相关文章

【开源工程】超经典实景三维数字孪生矿山~智慧矿山解决方案

飞渡科技数字孪生煤矿管理平台&#xff0c;以数字孪生技术为底座&#xff0c;融合图像识别、电磁感应、5G下井等技术&#xff0c;实现矿山环境、采煤装备、移动巡检等生产数据的全面采集&#xff0c;实时感知生产过程与关键装备的运行数据和状态&#xff0c;逐步推进矿山全流程…

Python爬虫从基础到入门:script标签中的数据

上一篇文章: Python爬虫从基础到入门:script标签中的数据 1. 分析需要抓取的数据的在哪?2. 获取数据、解析数据3. 下载视频、音频文件4. 参考代码1. 分析需要抓取的数据的在哪? 本篇博文以B站视频为例,B站视频在用户没有登录的状态下,只能观看视频尺寸为360流畅,在登录…

深度剖析Kafka中Coordinator的奥秘

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 深度剖析Kafka中Coordinator的奥秘 前言什么是Coordinator&#xff1f;Group Coordinator&#xff08;群组协调器&#xff09;&#xff1a;Transaction Coordinator&#xff08;事务协调器&#xff09…

一文让您读懂实时数仓(Apache Doris)

引言&#xff1a; 随着大数据时代的来临&#xff0c;实时数据处理与分析成为企业核心竞争力的关键因素之一。在这场数据革命中&#xff0c;SelectDB成为引领者。从百度自研的实时数仓平台 Palo&#xff0c;到开源项目 Apache Doris&#xff0c;再到飞轮科技研发的 SelectDB&am…

程序人生——Java数组和集合使用建议(1)

目录 引出数组和集合建议60&#xff1a;性能考虑&#xff0c;数组是首选建议61&#xff1a;若有必要&#xff0c;使用变长数组建议62&#xff1a;警惕数组的浅拷贝 建议63&#xff1a;在明确的场景下&#xff0c;为集合指定初始容量建议64&#xff1a;多种最值算法&#xff0c;…

使用opencv进行图片分析

opencv学习 一、配置环境并打开编译器 配置opencv在你的任意一个盘里创建一个专属于opencv的文件夹便于学习与整理 打开控制台winr输入cmd&#xff0c;进入后输入conda activate opencv&#xff0c;进入环境以后进入你所设置的opencv文件的盘&#xff0c;我的是D盘&#xff0…

php.exe运行时,提示缺少VCRUNTIME140.dll

php.exe运行时&#xff0c;提示缺少VCRUNTIME140.dll 下载地址 https://www.microsoft.com/zh-cn/download/details.aspx?id48145根据需要选择下载3.运行安装后&#xff0c;再次运行php.exe。

javaweb篇请求与相应的参数问题

目录 目录 前言 简单传参设置 get请求无法识别 post请求 简单传参问题无法识别的解决问题 注意事项 改法 实体参数 代码展示&#xff08;1&#xff09;------单个私有类 代码展示&#xff08;2&#xff09;----多个私有类 实现服务器的部署以及实参的传递 今日分享…

B3620 x 进制转 10 进制(详解)

题目 思路 八进制数567怎么转化为十进制数。首先八进制就是逢八进一&#xff0c;也就是说这里面最大的数也就7&#xff0c;没有≥8的数。下面我们就讲一下567怎么转化为十进制&#xff1a;首先7是个位&#xff0c;可以直接写成十进制的7&#xff0c;6是十位&#xff0c;它是通…

图片制作二维码能批量生成吗?快捷在线制作二维码的技巧

现在很多场景下获取内容的方式都会通过扫描二维码来获取&#xff0c;比如常见的有文本内容、图片照片、音频视频等。二维码制作的方法也越来越简单&#xff0c;只需要通过二维码生成器的功能就可以快速完成&#xff0c;那么如果需要将多张图片每一张单独生成二维码使用时&#…

虚幻引擎5比Maya更好用吗?来看看Maya大神眼中的虚幻引擎5

这两年&#xff0c;大家总在争论&#xff1a; 虚幻引擎5&#xff08;UE5&#xff09;比Maya更好用吗&#xff1f; 未来会替代Maya吗&#xff1f; 虚幻引擎5(UE5)的快速发展&#xff0c;让许多传统Maya动画师感到焦虑和迷茫。但不要担心&#xff0c;这篇文章旨在解决你的困扰。…

Springboot——JSR303校验

1. 请求参数的合法性校验 使用基于JSR303的校验框架实现&#xff0c;Springboot提供了JSR-303的支持&#xff0c;它就是spring-boot-starter-validation&#xff0c;他包括了很多的校验规则&#xff0c;只需要在模型中通过注解指定校验规则&#xff0c;在Controller方法上开启校…

激活函数理解

前言 为什么神经网中非要有各种各样的激活函数&#xff1f;他们有什么用&#xff1f;没有他们会怎样&#xff1f;常见的激活函数有哪些&#xff0c;他们都有什么特点&#xff1f; 如果我们不运用激活函数&#xff0c;神经网络的输出信号将仅仅是一个简单的线性函数。线性方程…

Docker 容器化技术:构建高效、可移植的开发环境和部署流程|Docker 网络

为了支持网络协议栈的多个实例&#xff0c;Linux 在网络协议栈中引入了网络命名空间。这些独立的协议栈被隔离到不同的命名空间中&#xff0c;处于不同命名空间中的网络协议栈是完全隔离的&#xff0c;彼此无法通信。通过对网络资源的隔离&#xff0c;就能在一台宿主机上虚拟多…

FFmepg--视频编码流程--yuv编码为h264

文章目录 基本概念流程api核心代码 基本概念 YUV格式&#xff1a;是一种颜色编码方式&#xff0c;YUV分别为三个分量&#xff1a;‘Y’是明亮度&#xff0c;也就是灰度值&#xff1b;‘U’和‘V’是色度 YUV格式的分类&#xff1a; planar的YUV格式&#xff1a;先存储planar的…

初步了解序列化和反序列化

01什么是序列化和反序列化 序列化是将对象转化为字符串以便存储的一种方式。而反序列化恰好是序列化的逆过程&#xff0c;反序列化会将字符串转化为对象供程序使用。 常见的php系列化和反系列化方式主要有&#xff1a;serialize&#xff0c;unserialize&#xff1b;json_enco…

姿态旋转的哥氏定理以及速度微分的推导

姿态旋转中涉及到坐标系的转换&#xff0c;在有相对旋转的两个坐标系中观察一个向量的变化&#xff0c;用到了哥氏定理。 例如在i系中观察e系下的运动&#xff0c;则 哥氏定理的公式 wie是e相对于i的角运动 注意符号i在前e在后。 wie是e相对于i的角运动 注意符号i在前e在…

R语言:如何基于地球外辐射(Ra)和相对日照(n/N)计算太阳辐射Rs?

正在编写相关软著&#xff0c;借此机会了解R语言的基本语法和一些处理流程&#xff0c;所以解释稍微繁琐。 Note&#xff1a; 使用的R语言版本是 R version 4.3.2 (2023-10-31 ucrt) 使用的RStudio编辑器版本是&#xff1a; 01 基于随机森林的插值填补缺失值 这是目前处理…

深入探索C与C++的混合编程

实现混合编程的技术细节 混合使用C和C可能由多种原因驱动。一方面&#xff0c;现有的大量优秀C语言库为特定任务提供了高效的解决方案&#xff0c;将这些库直接应用于C项目中可以节省大量的开发时间和成本。另一方面&#xff0c;C的高级特性如类、模板和异常处理等&#xff0c;…

mysql数据库中查询重复数据和去重数据

文章目录 1.查找重复数据2. 查到重复组的唯一数据3.删除重复数据4.注意重复的内容和删除的记录数是否一致 1.查找重复数据 select gene_entrez_id,count(*) a from diag_gene GROUP BY gene_entrez_id HAVING a > 12. 查到重复组的唯一数据 原理 分组后如果组内多个数据…