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) {	
 		 //判断释放锁的时间是否为-1
        if (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脚本后
在这里插入图片描述

释放锁

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

人工智能|深度学习——多模态条件机制 Cross Attention 原理及实现

一、引入 虽然之前写过 Attention 的文章&#xff0c;但现在回头看之前写的一些文章&#xff0c;感觉都好啰嗦&#xff0c;正好下一篇要写的 Stable Diffusion 中有 cross-attention&#xff0c;索性就再单拎出来简单说一下 Attention 吧&#xff0c;那么这篇文章的作用有两个&…

图搜索算法详解与示例代码

在计算机科学领域&#xff0c;图搜索算法是一类用于在图数据结构中查找特定节点或路径的算法。图搜索算法在许多领域都有着广泛的应用&#xff0c;包括网络路由、社交网络分析、游戏开发等。本文将详细介绍几种常见的图搜索算法&#xff0c;包括深度优先搜索&#xff08;DFS&am…

大数据技术就业和发展前景怎么样

大数据技术的就业和发展前景极为乐观&#xff0c;具有行业需求旺盛、就业多样性、可持续发展潜力等特点&#xff0c; 上大学网 &#xff08;www.sdaxue.com&#xff09;整理出了大数据技术的就业和发展前景以下几个关键趋势&#xff0c;供大家参考&#xff01; 行业需求旺盛&…

链表例题(分割链表)

链接&#xff1a; . - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 即将小于特定值的节点放在前面&#xff0c;大于特定值的节点接在后面 思路&#xff1a; 我们可以创建两个链表分别存放大于的值和小于的值。5个变量&#xff08;记录链表当前位置的指针st…

【开发技巧 | 第一篇】Typora快捷键方式给字体添加颜色

文章目录 1.Typora快捷键方式给字体添加颜色1.1下载并安装AutoHotkey1.2新建ahk脚本文件1.3运行ahk脚本文件1.4小结 1.Typora快捷键方式给字体添加颜色 1.1下载并安装AutoHotkey 点击下载: https://autohotkey.com/download/ahk-install.exe下载安装包&#xff0c;执行安装&a…

前端开发攻略---介绍HTML中的<dialog>标签,浏览器的原生弹框。

1、演示 2、介绍 <dialog> 标签用于定义对话框&#xff0c;即一个独立的窗口&#xff0c;通常用来显示对话框、提示框、确认框等弹出式内容。在对话框中&#xff0c;可以包含文本、表单元素、按钮等内容&#xff0c;用户可以和这些内容进行交互。 3、兼容性 4、示例代码 …

02 spring-boot+mybatis+elementui 的登录,文件上传,增删改查的入门级项目

前言 主要是来自于 朋友的需求 项目概况 就是一个 学生信息的增删改查 然后 具体到业务这边 使用 mybatis xml 来配置的增删改查 后端这边 springboot mybatis mysql fastjson hutool 的一个基础的增删改查的学习项目, 简单容易上手 前端这边 node14 vue element…

ZABAPGIT问题,导入github上的程序包时报 DBSQL_DUPLICATE_KEY_ERROR

跟踪程序发现在94050行 INSERT seocompotx FROM TABLE it_descriptions 报的错 刚开始&#xff0c;不想着改动他&#xff0c;把seocompotx 表的数据做下指定清楚&#xff0c;但是5次清楚后&#xff0c;果断注释掉 改成 MODIFY seocompotx FROM TABLE it_descriptions。 在用…

算法训练营第十天 | LeetCode 232 用栈实现队列、LeetCode 225 用队列实现栈

栈的实现有顺序表和链式表两种&#xff0c;也就是数组和链表实现。 其中抽象栈类的私有成员函数有operator的重载函数和stack的构造函数&#xff0c;为了保护栈的构造和拷贝被保护。公有成员函数有Stack()&#xff0c;~Stack()&#xff0c;clear()&#xff0c;push()&#xff…

解决Redis的键值前出现类似\xAC\xED\x00\x05t\x00*这样的字符序列

文章目录 1.问题2.解决方法3.StringRedisTemplate和RedisTemplate的区别 1.问题 在使用RedisTemplate对Redis进行操作时,发现Reids键值对前有\xAC\xED\x00\x05t\x00*这样的字符序列 如图所示: 虽说不影响使用,但是听影响观感的 2.解决方法 查找了很多方法,可以指定RedisTem…

数据结构实验--实验02 栈的应用(数制转换及回文判断)

一、实验内容 二、算法实现 1、用栈的特性实现进转换的思路&#xff1a;参考手算求进制转换的思路——除r取余法&#xff0c;这里的r表示基数&#xff0c;8进制的基数就是8&#xff0c;那么将十进制数转换成8进制数手算的方法就是除8取余法&#xff0c;具体手算方法如图&#…

在安装有Acer软件保护卡的电脑上安装PRCS6

PRCS6下载地址https://www.yuque.com/u33774918/pqzsy8/gdo8n6hibxgzsghw 第一步&#xff0c;电脑开机进入windows系统 第二步&#xff0c;解压PRCS6到电脑桌面 第三步&#xff0c;打开电脑桌面的PRCS6文件夹&#xff0c;双击‘点我安装’&#xff0c;开始安装 第四步&…

windows浅尝NW.js

windows浅尝NW.js 在本指南中&#xff0c;我们将详细介绍如何在windows上部署NW.js,实现应用的构成、启动方式、开发环境 环境部署 首先我们需要从官网下载对应的压缩包 (https://nwjs.io/downloads/) 下载完成后解压&#xff0c;可以看到对应的文件目录 然后我们运行目录下…

数据结构与算法实验题五道 A一元多项式的求导 B还原二叉树 C 六度空间 D 基于词频的文件相似度 E 模拟excel排序

A (1) 输入格式说明&#xff1a; 以指数递降方式输入多项式非零项系数和指数&#xff08;绝对值均为不超过1000的整数&#xff09;。数字间以空格分隔。 (2) 输出格式说明&#xff1a; 以与输入相同的格式输出导数多项式非零项的系数和指数。数字间以空格分隔&#xff0c;但…

ffmpeg中stream_loop参数不生效原因分析

问题 使用ffmpeg把一个视频文件发布成一个rtmp流&#xff0c;并设置成循环推流&#xff0c;此时需要使用参数stream_loop&#xff0c;命令如下: ffmpeg.exe -stream_loop -1 -re -i D:\tools\ffmpeg-5.1.2\bin\sei.h264 -c copy -f flv -safe 0 rtmp://localhost:1935/live/te…

【智能算法】鹦鹉优化算法(WO)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2024年&#xff0c;J Lian等人受到鹦鹉学习行为启发&#xff0c;提出了鹦鹉优化算法&#xff08;Parrot Optimizer, PO&#xff09;。 2.算法原理 2.1算法思想 PO灵感来自于在驯养的鹦鹉中观察到的…

go稀疏数组

稀疏数组 稀疏数组 稀疏数组 package testimport ("encoding/json""fmt""io/ioutil""log""reflect""testing" )type ValNode struct {Row int json:"row"Col int json:"col"Val int json:&qu…

分布式与一致性协议之Raft算法与一致哈希算法(一)

Raft算法 Raft与一致性 有很多人把Raft算法当成一致性算法&#xff0c;其实它不是一致性算法而是共识算法&#xff0c;是一个Multi-Paxos算法&#xff0c;实现的是如何就一系列值达成共识。并且&#xff0c;Raft算法能容忍少数节点的故障。虽然Raft算法能实现强一致性&#x…

黑马 - websocket搭建在线聊天室

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

通用漏洞评估系统CVSS4.0简介

文章目录 什么是CVSS&#xff1f;CVSS 漏洞等级分类历史版本的 CVSS 存在哪些问题&#xff1f;CVSS 4.0改进的“命名法”改进的“基本指标”考虑“OT/IOT”新增的“其他指标”CVSS 4.0存在的问题 Reference: 什么是CVSS&#xff1f; 在信息安全评估领域&#xff0c;CVSS为我们…