当前位置: 首页 > news >正文

springboot引入redisson分布式锁及原理

1.引入依赖

<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.13.6</version>
</dependency>

2.配置类创建bean

/*** @author qujingye* @Classname RedissonConfig* @Description TODO* @Date 2023/11/16 16:27*/
@Configuration
public class RedissonConfig {@Value("${spring.redis.host}")private String host;@Value("${spring.redis.port}")private String port;@Value("${spring.redis.password}")private String redisPassword;@Beanpublic RedissonClient redissonClient(){Config config = new Config();//单机模式  依次设置redis地址和密码config.useSingleServer().setAddress("redis://" + host + ":" + port).setPassword(redisPassword);return Redisson.create(config);}
}

3.yml配置

redis:database: 0host: localhostlettuce:pool:max-active: 8   #最大连接数据库连接数,设 0 为没有限制max-idle: 8     #最大等待连接中的数量,设 0 为没有限制max-wait: -1ms  #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。min-idle: 0     #最小等待连接中的数量,设 0 为没有限制shutdown-timeout: 100mspassword: 123456port: 6379

4.使用

@Resource
private RedissonClient redissonClient;// 创建锁对象
RLock redisLock = redissonClient.getLock("lock:xxxxx");
// 尝试获取锁
boolean isLock = redisLock.tryLock();
// 判断
if (!isLock) {// 获取锁失败,直接返回失败throw new CommonException(-1, "监测到文件" + originalFilename + ",正在导入请稍后在试!");
}
@Resource
private RedissonClient redissonClient;
@Test
void testRedisson() throws InterruptedException {// 获取锁(可重入),指定锁的名称RLock lock = redissonClient.getLock("anyLock"); // 尝试获取锁,参数分别是:获取锁的最大等待时间(期间会重试),锁自动释放时间,时间单位boolean isLock = lock.tryLock(1, 10, TimeUnit.SECONDS);// 判断释放获取成功if(isLock){try {System.out.println("执行业务");}finally {// 释放锁lock.unlock();}}
}

5.api方法简介

 //1. 普通的可重入锁RLock lock = redissonClient.getLock("generalLock");// 拿锁失败时会不停的重试// 具有Watch Dog 自动延期机制 默认续30s 每隔30/3=10 秒续到30slock.lock();// 尝试拿锁10s后停止重试,返回false// 具有Watch Dog 自动延期机制 默认续30sboolean res1 = lock.tryLock(10, TimeUnit.SECONDS);// 拿锁失败时会不停的重试// 没有Watch Dog ,10s后自动释放lock.lock(10, TimeUnit.SECONDS);// 尝试拿锁100s后停止重试,返回false// 没有Watch Dog ,10s后自动释放boolean res2 = lock.tryLock(100, 10, TimeUnit.SECONDS);//2. 公平锁 保证 Redisson 客户端线程将以其请求的顺序获得锁RLock fairLock = redissonClient.getFairLock("fairLock");

6.redisson原理

首先分布式锁要考虑
分布式锁需要考虑
互斥性 setnx
防死锁(过期,锁续命)
可重复性
高性能
而Redisson满足 实现了 锁续命 锁错删 可重入
[图片]

"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]);",

客户端线程在底层是如何实现加锁的:
第一步,redisson.getLock(“mylock”);可以获得一个 Redisson 的分布式锁对象,可以使用该对象进行加锁、释放锁、判断锁状态等操作。
第二步加锁,加锁的底层逻辑是通过lua脚本实现的,如果客户端线程第一次去加锁的话,
执行 ‘hincrby’ 会在key对应的hash数据结构当中,添加线程标识。HashKey 是UUID:TreadID value

  1. 来指定该线程当前对这个key已经加锁一次了,并且设置锁的过期时间为30秒
  2. 客户端线程是如何维持加锁的,当加锁成功后,此时会对加锁的结果设置一个监听器,如果监听到加锁成功了,也就是返回的结果时null,此时就会在后台通过watchdog 看门狗机制,
    启动一个后台的定时任务,每隔10秒执行一次,检查当前key依旧存在,就会重置key的存活时间为30秒,维持加锁,底层就是通过后台这样一个,线程定时刷新存活时间维系的(renewExpiration自己掉自己)
  3. 相同的客户端线程是如何实现可重入加锁的
    第一次加锁时 会往key对应的hash数据结构中 设置 UUID:ThreadID 1 表示当前线程对key 加锁一次
    如果相同线程再来对这个key加锁,只需要将UUID:ThreadID 持有锁的次数加1 即可 就为
    UUID:ThreadID 2 了,redisson底层就是通过这样的数据结构 来表示重入锁的
  4. 其他线程加锁失败时,底层是如何实现阻塞的
    通过key对应的hash结构当中的UUID:ThreadID 判断是否为当前线程id 如果不是则线程加锁失败
    如果没有获取锁的超时时间 此时就会进入一个 while 的死循环中 一直尝试加锁 直到加锁成功才会返回
  5. 客户端宕机了 锁如何释放的
    客户端宕机后 相应的watchdog 后台定时任务 当然已经没了 此时就无法对key 进行定时续期 那么当指定存活时间过后 key就会自动失效 锁就当然自动释放了
  6. 客户端如何主动释放持有的锁
"if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then " +"return nil;" +"end; " +"local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); " +"if (counter > 0) then " +"redis.call('pexpire', KEYS[1], ARGV[2]); " +"return 0; " +"else " +"redis.call('del', KEYS[1]); " +"redis.call('publish', KEYS[2], ARGV[1]); " +"return 1; " +"end; " +"return nil;",

客户端主动释放底层,也是通过执行lua脚本的方式来实现的
如果判断当前释放的key存在,并且在key的hash结构当中,存在当前线程的加锁信息,那么此时就会减扣当前线程,对这个key的重入锁次数,减扣线程的重入锁次数之后,如果当前线程在这个key的重入次数为0,此时就会直接释放锁,如果当前线程,在这个key中重入锁次数依然大于0。此时就直接重置一下,key的续期时间为30秒
7. 客户端尝试获取锁超时时间的机制底层是如何实现的

boolean isLock2 = redisLock.tryLock(1,TimeUnit.MINUTES);

如果在加锁时就指定 尝试获取锁的超时时间 如果获取锁失败 此时就不会永无止境的在while循环里面一直等待 ,而是根据你指定的锁超时时间,在这段时间范围获取不到锁,那么就会标记为获取锁失败,直接返回false
8. 客户端锁超时自动释放锁机制底层是怎么实现的

redisLock.lock(1, TimeUnit.MINUTES);

如果在加锁的时候指定了锁的超时时间,那么就算你获取锁成功了,也不会开启watch dog的定时任务,此时就将当前持有的这把锁的过期时间,设置为你指定的超时时间,那么你指定的时间到了之后,key失效被删除了,key对应的锁相应的也就自动释放了

相关文章:

springboot引入redisson分布式锁及原理

1.引入依赖 <dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.13.6</version> </dependency>2.配置类创建bean /*** author qujingye* Classname RedissonConfig* Description TOD…...

Linux驱动开发 问题随笔

1、内核空间与用户空间数据交换方式 分两种情况&#xff1a; 1> 需要交换的数据量较大时&#xff1b; 2> 需要交换的数据量较小时&#xff1b; 第一种情况使用以下的函数&#xff1a; unsigned long copy_to_user(void __user* to, const void* from, unsigned long n)…...

三分/01分数规划

三分 最小球覆盖 2018南京D 三分套三分套三分 constexpr int N105; struct node{int x,y,z; }a[N]; int n; double road(double x1,double y1,double z1,double x2,double y2,double z2){return sqrt((x1-x2)*(x1-x2)(y1-y2)*(y1-y2)(z1-z2)*(z1-z2)); } double check(double…...

大批卖家产品被下架!Temu又有新动作?

大批卖家产品被下架&#xff01;Temu又有新动作&#xff1f; 近日&#xff0c;Temu正式上线韩国站&#xff0c;截止目前已上线27个国家地区。Temu海外市场发展迅猛&#xff0c;外界的声音也褒贬不一。这其中最有发言权的&#xff0c;应该就是Temu平台的卖家了&#xff01; …...

STM32 LL库 TIM3定时器多通道捕获输入采集

为什么不用HAL库&#xff0c;使用HAL库捕获输入一个通道还尚可&#xff0c;多通道捕获由于HAL的回调函数不符合我的要求&#xff0c;干脆直接切换到LL库。网上找了许多&#xff0c;代码处理写的不符合我的要求&#xff0c;这里记录一下我的调试过程。 TIM2输出1路PWM信号&#…...

如何为初创企业选择合适的 ERP 系统?

**ERP系统**是制造、分销、供应链、金融、会计、风险管理等多个行业必不可少的企业技术解决方案。不论垂直行业、企业规模或目标受众如何&#xff0c;将ERP作为企业管理战略的核心部分都非常重要。 对于渴望发展的小型企业和初创企业来说&#xff0c;更是如此。大型企业需要对…...

jssip contact的随机字符串的问题

let configuration {sockets: [socket],uri: sip:1001127.0.0.1,}; 如果这样注册freesswitch&#xff0c;那么fs注册信息中的Contact字段信息就是&#xff1a;sip:sdfsdfsdfsfcvdwvdwd.invalid;transportws;fs_natyes;fs_path... 正确的写法是&#xff1a; //URI是jssip内置…...

别再吐槽大学教材了,来看看这些网友强推的数学神作!

前言 关于大学数学教材的吐槽似乎从来没停止过。有人慨叹&#xff1a;数学教材晦涩难懂。错&#xff01;难懂&#xff0c;起码还可以读懂。数学教材你根本读不懂&#xff1b;也有人说&#xff1a;数学教材简直就是天书。 数学教材有好有坏&#xff0c;这话不假&#xff0c;但更…...

Elasticsearch-汇总

Elasticsearch-基础介绍 跳转 分布式全文搜索引擎&#xff1a;包含【实时搜索】和【分析引擎】 Elasticsearch-倒排索引 跳转 倒排索引 跳转 Elasticsearch-Term Dictionary和Term Index 跳转 lucene-基础介绍 跳转 Elasticsearch-联合索引 跳转 Elasticsearch-Roaring B…...

9.3 【MySQL】系统表空间

了解完了独立表空间的基本结构&#xff0c;系统表空间的结构也就好理解多了&#xff0c;系统表空间的结构和独立表空间基本类似&#xff0c;只不过由于整个MySQL进程只有一个系统表空间&#xff0c;在系统表空间中会额外记录一些有关整个系统信息的页面&#xff0c;所以会比独立…...

STM32CUBEIDE生成hex文件 Release版本的下载不启动

现象描述&#xff1a; 使用STM32CUBEIDE生成hex文件&#xff0c;使用脱机下载器或者J-Flash下载到单片机中&#xff08;STM32F407&#xff09;单片机不启动。 测试其他的程序是可以启动的。 修改办法&#xff1a; 把Release版本切换到debug版本&#xff0c;重新编写&#xf…...

2023年亚太杯数学建模思路 - 复盘:校园消费行为分析

文章目录 0 赛题思路1 赛题背景2 分析目标3 数据说明4 数据预处理5 数据分析5.1 食堂就餐行为分析5.2 学生消费行为分析 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 赛题背景 校园一卡通是集…...

ceph集群移除物理节点

1. 概述 ceph分布式存储在生产或者实验环境&#xff0c;经常涉及到物理节点加入或者删除&#xff0c;本文仅对移除物理节点的相关步骤做了操作记录&#xff0c;以方便需要时查阅。 2. 移除物理节点 2.1 out掉相应osd 操作之前通过ceph -s确保整个集群状态是OK的&#xff0c;…...

(八)Spring源码解析:Spring MVC

一、Servlet及上下文的初始化 1.1> DispatcherServlet的初始化 对于Spring MVC来说&#xff0c;最核心的一个类就是DispatcherServlet&#xff0c;它负责请求的行为流转。那么在Servlet的初始化阶段&#xff0c;会调用init()方法进行初始化操作&#xff0c;在DispatcherSe…...

maven或者gradle打完jar,jekins启动提示找不到问题

1、记录下遇到的一个问题&#xff0c;maven或者gradle打完jar&#xff0c;然后jekins发布&#xff0c;启动提示找不到实体类&#xff0c;mapper&#xff0c;xml问题 2、首先排查jar包中这些文件是否存在 3、然后排查每层的包名或者文件名是否能对应上 我这次遇到的问题就是本地…...

浏览器缓存sessionStorage、localStorage、Cookie

一、sessionStorage 1、简介 sessionStorage用于在浏览器会话期间存储数据&#xff0c;数据仅在当前会话期间有效。 存储的数据在用户关闭浏览器标签页或窗口后会被清除。 2、方法 使用sessionStorage.setItem(key, value)方法将数据存储在sessionStorage中。使用sessionSt…...

易点易动固定资产管理系统场景应用一:集成ERP/财务系统

在企业的日常运营中&#xff0c;固定资产管理是一个重要而繁琐的任务。传统的手工管理方式往往效率低下且容易出错&#xff0c;给企业带来不必要的成本和风险。为了解决这一问题&#xff0c;易点易动固定资产管理系统应运而生。本文将重点介绍易点易动固定资产管理系统在集成ER…...

k8s部署elk8 直接通过logstash获取日志文件方式

配置文件 kibana [rootnode101 config]# cat kibana.yml # # ** THIS IS AN AUTO-GENERATED FILE ** ## Default Kibana configuration for docker target server.host: "0.0.0.0" server.shutdownTimeout: "5s" elasticsearch.hosts: [ "http:/…...

git 本地多个账号错乱问题解决

当我们在本地有多个git账号时&#xff0c;例如公司的gitlab有一个git账号&#xff0c;自己的开源项目有一个GitHub账号&#xff0c;我们可能会出现账号错乱的情况&#xff0c;例如提交到公司gitlab的代码是github账号 这种情况通常是由于您的git config配置文件中的用户信息未…...

wu-ui-uniapp 多平台快速开发的UI框架

WU-UI 多平台快速开发的UI框架(无论平台&#xff0c;一致体验) 官方群 wu-ui官方1群: 767943089 说明 wu-ui(如虎添翼) 是 全面兼容多端的uniapp生态框架&#xff0c;基于vue2、vue3和nvue开发。丰富组件库&#xff0c;便捷工具库&#xff0c;简单高效。无论平台&#x…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...

Golang——9、反射和文件操作

反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一&#xff1a;使用Read()读取文件2.3、方式二&#xff1a;bufio读取文件2.4、方式三&#xff1a;os.ReadFile读取2.5、写…...

实战设计模式之模板方法模式

概述 模板方法模式定义了一个操作中的算法骨架&#xff0c;并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下&#xff0c;重新定义算法中的某些步骤。简单来说&#xff0c;就是在一个方法中定义了要执行的步骤顺序或算法框架&#xff0c;但允许子类…...