Redisson分布式锁,重试锁和锁续命的原理

RedissonLock 锁重试原理

tryLock有三个三个参数,第一个是等待时间,第二个是锁失效后自动释放的时间,不填默认为-1,第三个是时间单位;
当设置了第一个参数,那这个锁就成了可重试锁;获取锁失败后,就不会立即返回了;会在等待内不断重试;如果在等待时间结束后,还没有获取到锁,那就失败了。
获取当前时间,线程ID,尝试获取锁,判断锁失效后自动释放的时间是否等于-1,如果不等于,就用自己的锁释放时间,如果等于-1,异步调用tryLockInnerAsync,返回值是个Future,第一个参数是等待时间,第二个参数是锁释放时间,看门狗的默认30秒,第三个是时间单位,第四个参数是线程ID,这个方法内是个lua脚本,成功返回空,是否返回过期时间;判断返回值是否为空,不为空,计算剩余等待时间,判断等待时间>0,大于就去尝试获取锁,但不是立即获取锁,是在剩余等待时间内订阅了锁释放的情况(锁释放的时候会发布通知),返回值也是个Future,如果超时了,会取消订阅;如果锁已经释放了,计算剩余等待时间,判断剩余等待时间>0,开始循环,就可以重新获取锁,和上面一样,如果失败,同时上,但这里用的是信号量。

在这里插入图片描述
lock.tryLock方法

第一个参数(等待时间),如果设置了,获取锁失败后,就不会立即返回了;会在等待内不断重试;如果在等待时间结束后,还没有获取到锁,那就失败了。所以设置后就变成了可重试的锁了。
第二个参数(锁失效后自动释放的时间,不填默认为-1)
第三个参数(时间单位)
源码跟进

在这里插入图片描述

第二个参数没给,默认值-1,跟进去tryLock方法看看

在这里插入图片描述

在这里插入图片描述
跟进tryAcquire方法,尝试获取锁
在这里插入图片描述
跟进tryAcquireAsync方法

//源码private <T> RFuture<Long> tryAcquireAsync(long waitTime, long leaseTime, TimeUnit unit, long threadId) {	//判断释放锁的时间是否为-1if (leaseTime != -1L) {//用自己的释放锁的时间return this.tryLockInnerAsync(waitTime, leaseTime, unit, threadId, RedisCommands.EVAL_LONG);} else {//如果是-1,设置一个默认的释放锁的时间,30秒(getLockWatchdogTimeout)RFuture<Long> ttlRemainingFuture = this.tryLockInnerAsync(waitTime, this.commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(), TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);ttlRemainingFuture.onComplete((ttlRemaining, e) -> {if (e == null) {if (ttlRemaining == null) {this.scheduleExpirationRenewal(threadId);}}});return ttlRemainingFuture;}}

在这里插入图片描述
跟进getLockWatchdogTimeout看门狗

显示默认30秒
在这里插入图片描述
返回RedissonLock类,继续跟进tryLockInnerAsync方法

tryLockInnerAsync 异步方法,有没有拿到结果不清楚

在这里插入图片描述

看到有lua脚本

lua脚本
判断锁是否存在
不存在设置锁标识,v+1
设置有效期
存在,判断锁是不是我自己的
是,v+1
设置有效期
成功获取锁,返回空
失败,返回锁的有效期(毫秒)

  <T> RFuture<T> tryLockInnerAsync(long waitTime, long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {//释放锁的时间,记录到本地一个成员变量里this.internalLockLeaseTime = unit.toMillis(leaseTime);return this.evalWriteAsync(this.getName(), LongCodec.INSTANCE, command, "if (redis.call('exists', KEYS[1]) == 0) then redis.call('hincrby', KEYS[1], ARGV[2], 1);redis.call('pexpire', KEYS[1], ARGV[1]); return nil; end; if (redis.call('hexists', KEYS[1], ARGV[2]) == 1)then redis.call('hincrby', KEYS[1], ARGV[2], 1);redis.call('pexpire', KEYS[1], ARGV[1]); return nil; end;return redis.call('pttl', KEYS[1]);", Collections.singletonList(this.getName()), this.internalLockLeaseTime, this.getLockName(threadId));}

一步一步往上返回,返回到RedissonLock类中的tryLock方法的tryAcquire方法,结果有两种,一种是获取锁成功返回值为空,另一种是获取锁失败返回值为锁释放的时间

在这里插入图片描述
继续

在这里插入图片描述

锁续命

当用默认的锁释放时间时,且已经拿到锁,会创建一个 ConcurrentMap来存锁的记录,以锁的名称为k,线程id为V,判断是否第一次来,如果是开启一个延时任务,10秒后执行,执行的就是更新有效期的lua脚本,更新成功后,开始递归,无限续约。

先看锁释放时间是默认值-1的情况
在这里插入图片描述
跟进 scheduleExpirationRenewal 方法
在这里插入图片描述
跟进 renewExpiration 方法
在这里插入图片描述
跟进 renewExpirationAsync 方法

判断锁是不是当前线程拿到的,是就重置有效期

   protected RFuture<Boolean> renewExpirationAsync(long threadId) {return this.evalWriteAsync(this.getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, "if (redis.call('hexists', KEYS[1], ARGV[2]) == 1)then redis.call('pexpire', KEYS[1], ARGV[1]); return 1; end; return 0;",Collections.singletonList(this.getName()), this.internalLockLeaseTime, this.getLockName(threadId));}

执行lua脚本后
在这里插入图片描述

释放锁

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

C++的演变与未来:编程艺术的持续进化

在计算机编程的演变历程中&#xff0c;C以其独特的魅力和强大的功能&#xff0c;一直占据着不可或缺的地位。从最初的面向对象编程&#xff0c;到如今的跨平台、高性能应用&#xff0c;C在不断地适应和推动着计算机技术的发展。本文将深入剖析C的演变过程&#xff0c;展望其未来…

C++ 优先级队列priority_queue

1、常用接口 底层使用的是堆实现&#xff0c;默认为大堆 2、理解&#xff1a; 优先级队列就是即使插入的是一个乱序的&#xff0c;但是依旧会按照有序的顺序出队列 优先级队列就是会根据大小来出队列&#xff0c;而不是谁在队头就出谁。 优先级队列底层是使用堆实现&#x…

Java项目:基于SSM框架实现的实践项目管理系统(ssm+B/S架构+源码+数据库+毕业论文+开题报告)

一、项目简介 本项目是一套基于SSM框架实现的实践项目管理系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff…

【前端】-【防止接口重复请求】

文章目录 需求实现方案方案一方案二方案三 需求 对整个的项目都做一下接口防止重复请求的处理 实现方案 方案一 思路&#xff1a;通过使用axios拦截器&#xff0c;在请求拦截器中开启全屏Loading&#xff0c;然后在响应拦截器中将Loading关闭。 代码&#xff1a; 问题&…

Coursera: An Introduction to American Law 学习笔记 Week 04: Constitutional Law

An Introduction to American Law 本文是 https://www.coursera.org/programs/career-training-for-nevadans-k7yhc/learn/american-law 这门课的学习笔记。 文章目录 An Introduction to American LawInstructors Week 04: Constitutional LawKey Constitutional Law TermsSup…

黑马 - websocket搭建在线聊天室

这里写自定义目录标题 一、消息推送常见方式二、websocket 是什么&#xff1f;三、websocket api的介绍1、客户端 &#xff08;浏览器&#xff09; 四、实现在线聊天室1、需求2、聊天室流程分析3、消息格式4、代码实现 一、消息推送常见方式 1、轮训方式 2、SSE&#xff08;…

2024年第二十一届 五一杯 (A题)大学生数学建模挑战赛 | 多目标优化问题,深度学习分析 | 数学建模完整代码解析

DeepVisionary 每日深度学习前沿科技推送&顶会论文&数学建模与科技信息前沿资讯分享&#xff0c;与你一起了解前沿科技知识&#xff01; 本次DeepVisionary带来的是五一杯的详细解读&#xff1a; 完整内容可以在文章末尾全文免费领取&阅读&#xff01; 第一个问题…

【Linux】进程终止

思维导图 学习内容 进程终止是进程控制里面的一个重要的知识&#xff0c;通过这一篇博客&#xff0c;我们可以学习到进程终止的概念&#xff0c;进程终止的三种情况&#xff0c;进程终止的退出码和退出信号&#xff0c;最后在来学习进程是如何进行终止的。 学习目标 进程终止…

诺基亚贝尔探访上海斯歌,共探创新合作新机遇

近日&#xff0c;上海斯歌K2 BPM迎来重要客户考察交流活动。来自诺基亚贝尔的首席数字官刘少勇一行莅临了上海斯歌K2 BPM 的武汉研发中心&#xff0c;并对上海斯歌在BPM业务流程管理领域的研发成果及交付能力给予了高度肯定。 此次活动不仅加深了双方的战略合作&#xff0c;也为…

维修家政按摩到家上门小程序开源版开发

维修家政按摩到家上门小程序开源版开发 智能定位&#xff0c;精准计费——全新上门服务平台功能解析。 全新上门服务平台已经上线&#xff0c;它拥有一系列强大的功能&#xff0c;旨在为用户提供最便捷、最个性化的服务体验。 !](https://img-blog.csdnimg.cn/direct/86195e…

WCH RISC CH32V303RCT6 单片机的SDI Printf 虚拟串口功能 类似SEGGER RTT打印功能 简单分析

参考&#xff1a; 有关于 SDI printf 更多的信息和资料吗&#xff1f; 关于 CH32 系列 MCU SDI 虚拟串口功能的使用 【CH32X035 评估板测评】 教你使用 SDI 接口重定向 printf SDI (Serial Data Interface) 是沁恒微电子 RISC-V 内核的私有外设接口,CH32 RISC-V 系列目前提供了…

redis 高可用 Sentinel 详解

写在前面 redis 在我们日常的业务开发中是十分常见的&#xff0c;而redis的可用性就必须要有很高的要求&#xff0c;那么 redis集群的高可用由有一个或者多个 Sentinel(哨兵) 实例组成的 哨兵系统来保证的。 哨兵 由一个或者多个 Sentinel 实例组成的 Sentinel 系统可以监控任…

53.HarmonyOS鸿蒙系统 App(ArkTS) socket套接字连接失败无效参数--invalid argument

ark ts socket套接字连接失败无效参数--invalid argument 绑定本机真实连接的WIFI的IP&#xff0c;不要绑定127.0.0.1

VS code 同步odata服务

在做UI5得开发过程中&#xff0c;经常会出现odata需要更新 那么已经加载过得项目如何去跟新odata服务呢 可以通过如下步骤 1.右键打开应用信息 2.找到manage service models 3.点击编辑 4.选中 刷新并保存

《STM32 HAL库》中断相关函数详尽解析——NVIC

观前提醒&#xff1a;本文以外部中断点灯为例&#xff0c;分析了HAL库中中断服务相关函数的使用及相互关联、底层原理 一、实例实现 实例简介&#xff1a;主函数控制LED2进行闪烁&#xff0c;中断控制LED0开关 我们先使用CubeMX创建项目文件&#xff1a; 1、在System Core中配…

XY_RE复现(五)

一&#xff0c;给阿姨倒一杯卡布奇诺 是一道魔改TEA加密 给出了一些初始化&#xff0c;然后输入的flag拆分&#xff0c;两两一组&#xff0c;通过for循环放入encrypt加密函数 #include <stdio.h> #define uint32_t unsigned intvoid decrypt(uint32_t *v, uint32_t *ke…

【STM32F407+CUBEMX+FreeRTOS+lwIP netconn UDP TCP记录】

STM32F407CUBEMXFreeRTOSlwIP netconn UDP TCP记录 注意UDPUDP1UDP2 TCPTCP clientTCP server图片 注意 1、超时 #include “lwipopts.h” #define LWIP_SO_RCVTIMEO 12、先保证能ping通 3、关于工程创建可参考 【STM32F407CUBEMXFreeRTOSlwIP之UDP记录】 4、…

数据仓库Data Warehouse

数据仓库Data Warehouse 数仓是一种思想,数仓是一种规范,数仓是一种解决方案 1. 数据处理方式 数据处理大致可以分成两大类: 联机事务处理OLTP(on-line transaction processing)联机分析处理OLAP(On-Line Analytical Processing)1.1. OLTP OLTP的全称是On-line Transa…

【C++】详解string类

目录 简介 框架 构造 全缺省构造函数 ​编辑 传对象构造函数 拷贝构造 析构函数 容量 size() capacity&#xff08;&#xff09; empty() clear() reserve() ​编辑 resize() 遍历 检引用符号"[ ]"的重载 迭代器 begin() end() rbegin() rend(…

使用Mybatis映射时间 DateTime ==> LocalDateTime

首先查看&#xff0c;数据库字段&#xff1a; 书写映射实体类对象VO&#xff1a; Data public class OrderListVO implements Serializable {private Integer orderId;private String memberName;private String orderNumber;private BigDecimal orderPrice;private String l…