Redisson分布式锁使用详解

引言

日常开发中,难免遇到一些并发的场景,为了保证接口执行的一致性,通常采用加锁的方式,因为服务是分布式部署模式,本地锁Reentrantlock和Synchnorized这些就先放到一边了,Redis的setnx锁存在无法抱保证原子性的问题就暂时搁且到一边,直接上大招Redisson也是我最近开发项目中基本都在用的缓存,并且也都是用它的分布式锁机制。

为什么要使用分布式锁

在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,这个时候,便需要使用到分布式锁。

目前几乎很多大型网站及应用都是分布式部署的,如何保证分布式场景中的数据一致性问题一直是一个比较重要的话题。在某些场景下,为了保证数据的完整性和一致性,我们需要保证一个方法在同一时间内只能被同一个线程执行,这就需要使用分布式锁。

分布式锁需满足四个条件

为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:

  1. 互斥性。在任意时刻,只有一个客户端能持有锁。

  2. 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。

  3. 解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了,即不能误解锁。

  4. 具有容错性。只要大多数Redis节点正常运行,客户端就能够获取和释放锁。

Redisson 分布式锁实现原理图

Redisson分布式锁常规使用 

关于Redisson的一些基本概念,本章就不做太详细的说明了,有兴趣的小伙伴可以自己去了解下,主要说下加锁的常规使用,Redisson分布式锁是基于Redis的Rlock锁,实现了JavaJUC包下的Lock接口。

Lock

public void getLock(){//获取锁RLock lock = redisson.getLock("Lxlxxx_Lock");try {// 2.加锁lock.lock();} catch (InterruptedException e) {e.getStackTrace();} finally {// 3.解锁lock.unlock();System.out.println("Finally,释放锁成功");}

getLock获取锁,lock.lock进行加锁,会出现的问题就是lock拿不到锁一直等待,会进入阻塞状态,显然这样是不好的。

TryLock 

返回boolean类型,和Reentrantlock的tryLock是一个意思,尝试获取锁,获取到就返回true,获取失败就返回false,不会使获不到锁的线程一直处于等待状态,返回false可以继续执行下面的业务逻辑,当然Ression锁内部也涉及到watchDog看门狗机制,主要作用就是给快过期的锁进行续期,主要用途就是使拿到锁的有限时间让业务执行完,再进行锁释放。

RLock lock = redisson.getLock(name);
try {if (lock.tryLock(2, 10, TimeUnit.SECONDS)) {//执行业务逻辑} else {System.out.println("已存在");}
} catch (InterruptedException e) {e.printStackTrace();
}finally {
//判断当前线程持有的锁是不是处于锁定状态,锁定状态再进行释放if (this.redissonLock.isHeldByCurrentThread(lockName)) {this.redissonLock.unlock(lockName);}
}

自定义注解实现锁机制

通常我们都会将redisson实例注入到方法类里面,然后调用加锁方法进行加锁,如果其他业务方法也需要加锁执行,将会产生很多重复代码,由此采用AOP切面的方式,只需要通过注解的方式就能将方法进行加锁处理。

自定义注解

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DistributedLock {String key() default "";int leaseTime() default 10;boolean autoRelease() default true;String errorDesc() default "系统正常处理,请稍后提交";int waitTime() default 1;
}

切面类实现 

@Aspect
@Component
public class DistributedLockHandler {private static final Logger log = LoggerFactory.getLogger(DistributedLockHandler.class);@AutowiredRedissonLock redissonLock;public DistributedLockHandler() {}@Around("@annotation(distributedLock)")public Object around(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable {String lockName = this.getRedisKey(joinPoint, distributedLock);int leaseTime = distributedLock.leaseTime();String errorDesc = distributedLock.errorDesc();int waitTime = distributedLock.waitTime();Object var8;try {boolean lock = this.redissonLock.tryLock(lockName, (long)leaseTime, (long)waitTime);if (!lock) {throw new RuntimeException(errorDesc);}var8 = joinPoint.proceed();} catch (Throwable var12) {log.error("执行业务方法异常", var12);throw var12;} finally {if (this.redissonLock.isHeldByCurrentThread(lockName)) {this.redissonLock.unlock(lockName);}}return var8;}/***  获取加锁的key* @param joinPoint* @param distributedLock* @return*/private String getRedisKey(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) {String key = distributedLock.key();Object[] parameterValues = joinPoint.getArgs();MethodSignature signature = (MethodSignature)joinPoint.getSignature();Method method = signature.getMethod();DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();String[] parameterNames = nameDiscoverer.getParameterNames(method);if (StringUtils.isEmpty(key)) {if (parameterNames != null && parameterNames.length > 0) {StringBuffer sb = new StringBuffer();int i = 0;for(int len = parameterNames.length; i < len; ++i) {sb.append(parameterNames[i]).append(" = ").append(parameterValues[i]);}key = sb.toString();} else {key = "redissionLock";}return key;} else {SpelExpressionParser parser = new SpelExpressionParser();Expression expression = parser.parseExpression(key);if (parameterNames != null && parameterNames.length != 0) {EvaluationContext evaluationContext = new StandardEvaluationContext();for(int i = 0; i < parameterNames.length; ++i) {evaluationContext.setVariable(parameterNames[i], parameterValues[i]);}try {Object expressionValue = expression.getValue(evaluationContext);return expressionValue != null && !"".equals(expressionValue.toString()) ? expressionValue.toString() : key;} catch (Exception var13) {return key;}} else {return key;}}}
}

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

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

相关文章

九-2、Rocky Linux软件包管理与安装 学习笔记

1. DNF的rocky linux管理 DNF: Dandified YUM,基于RPM的Linux软件包管理器&#xff0c;是YUM的下一代版本。 Dnf命令和yum命令兼容&#xff0c;依然使用yum仓库。 dnf module在软件安装上更方便&#xff0c;可以通过dnf module install 在安装软件时指定安装的版本&#xff0…

QT开发(QT的基本概述和环境的安装)

QT的概述 一.QT的介绍背景1.1 什么是QT1.2QT的发展史1.3 Qt支持的平台1.4QT版本1.5QT的优点1.6QT的应用场景 二.搭建QT开发环境2.1 QT的开发工具的下载2.2 QT环境变量配置 三.QT的三种基类四.QT Hello World程序4.1使用按钮实现4.1.1 代码方式实现4.1.2 可视化操作实现 一.QT的…

【C#】在一个给定的宽、高范围内,获取到该多边形内部的所有坐标集合?

问题点 使用C#语言在一个给定的宽、高范围内&#xff0c;获取到该多边形内部的所有坐标集合&#xff1f; 这个多边形可能存在交叉及互相重叠部分 图像的宽、高可以定义为&#xff1a;2000*2000 多边形坐标集合&#xff1a;Point[] polygon_points new Point[] { new Point…

如何在vscode中对在服务器上多卡运行的bash脚本进行debug?

问题描述 使用vscode可以很方便地添加断点&#xff0c;进行代码调试。 在使用服务器时&#xff0c;我们的python代码通常是通过bash脚本来执行的&#xff0c;那么如何进行debug呢&#xff1f; 待运行的bash 脚本示例 前半段定义了一些参数&#xff0c;后半段是执行python代码…

数据结构的概念和术语

目录 一.前言 二.数据结构的基本概念 三.数据结构的术语 一.前言 数据结构是一门研究非数值计算的程序设计中计算机的操作对象以及它们之间的关系和操作的学科。数据结构的基本数据结构包括两部分&#xff0c;线性结构跟非线性结构。 二.数据结构的基本概念 数据结构主要包括…

压测实操--kafka broker压测方案

作者&#xff1a;九月 环境信息&#xff1a; 操作系统centos7.9&#xff0c;kafka版本为hdp集群中的2.0版本。 kafka broker参数 num.replica.fetchers&#xff1a;副本抓取的相应参数&#xff0c;如果发生ISR频繁进出的情况或follower无法追上leader的情况则适当增加该值&…

CTF ssrf 基础入门

0x01 引言 我发现我其实并不是很明白这个东西&#xff0c;有些微妙&#xff0c;而且记忆中也就记得Gopherus这个工具了&#xff0c;所以重新学习了一下&#xff0c;顺便记录一下吧 0x02 辨别 我们拿到一个题目&#xff0c;他的名字可能就是题目类型&#xff0c;但是也有可能…

【使用 Pytest 记录日志文件并确保测试用例正常执行】

1. 更新测试脚本 首先&#xff0c;确保你的测试脚本 wifi_test.py 配置了日志记录&#xff0c;并包含所有测试用例&#xff1a; import subprocess import time import logging import pytest import sys# 配置日志记录 logging.basicConfig(filenamewifi_test.log, levellog…

vue侦听器(Watch)精彩案例剖析一

目录 watch介绍 监视普通数据类型 监视对象类型 watch介绍 在 Vue 中,watch主要用于监视数据的变化,并执行相应操作。一旦被监视的属性发生变化,回调函数将自动被触发。当在 Vue 中使用watch来响应数据变化时,首先要清楚,watch本质上是一个对象,且必须以对象的…

HDShredder 7 企业版案例分享: 依照国际权威标准,安全清除企业数据

HDShredder 7 企业版用户案例 天津鸿萌科贸发展有限公司是德国 Miray 公司 HDShredder 数据清除软件的授权代理商。近日&#xff0c;上海某网络科技有限公司采购 HDShredder 7 企业版x4&#xff0c;为公司数据存储资产的安全清除工作流程配备高效的执行工具。HDShredder 7 企业…

划分型dp,CF 1935C - Messenger in MAC

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 1935C - Messenger in MAC 二、解题报告 1、思路分析 比较简单的思路是反悔贪心&#xff0c;这里不展开说了&#xff0c;来说一下dp的做法 由于式子里面带绝对值&#xff0c;很烦&#xff0c;我们将pair按…

Bootstrap实现dialog上一步下一步多个弹窗交互

Bootstrap实现dialog上一步下一步多个弹窗交互 版本介绍&#xff1a; Bootstrap v3.3.7jQuery v3.5.1 一、功能介绍 重新设置bootstrap主题色内容区以card形式展示&#xff0c;纯js实现分页功能共两步骤&#xff0c;第一步选择模板&#xff0c;第二步进行其他操作步骤一内的按…

特征工程在机器学习中的重要性

特征工程在机器学习中的重要性 特征工程在机器学习中占据着至关重要的地位&#xff0c;它是连接原始数据与机器学习模型之间的桥梁。通过特征工程&#xff0c;我们可以将原始数据转换为机器学习算法能够有效利用的形式&#xff0c;从而提高模型的性能和准确性。以下是特征工程…

JAVA毕业设计153—基于Java+Springboot+小程序的校园维修管理系统小程序(源代码+数据库)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringboot小程序的校园维修管理系统小程序(源代码数据库)153 一、系统介绍 本项目分为用户、维修员、管理员三种角色 1、用户&#xff1a; 注册、登录、报修申报、报修…

师资培训丨AIGC 技术与大模型应用开发实战线下广州班莅临泰迪智能科技参观调研

7月23日&#xff0c;2024年第二期全国数字人才技能提升师资培训班——AIGC 技术与大模型应用开发实战线下广州班莅临广东泰迪智能科技股份有限公司产教融合实训基地参观调研&#xff0c;来自全国各地三十多名高校教师参与本次活动。泰迪智能科技董事长张良均、校企合作经理吴桂…

【Gin】架构的精妙编织:Gin框架中组合模式的革新实践与技术深度解析(上)

【Gin】架构的精妙编织&#xff1a;Gin框架中组合模式的革新实践与技术深度解析(上) 大家好 我是寸铁&#x1f44a; 【Gin】架构的精妙编织&#xff1a;Gin框架中组合模式的革新实践与技术深度解析(上)✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 本次文章分为上下两部分…

【区块链+绿色低碳】基于区块链的企业碳管理平台 | FISCO BCOS应用案例

在当今全球气候变化和环境问题日益严重的背景下&#xff0c;碳减排已成为全球共同面临的重要任务。作为能源消耗大户&#xff0c; 现代企业必须认识到碳减排的重要性&#xff0c;并采取有效措施实现碳减排。通过完善碳资产管理&#xff0c;企业可以清晰地了解 自身的碳排放情况…

矩估计与最大似然估计的通俗理解

点估计与区间估计 矩估计与最大似然估计都属于点估计&#xff0c;也就是估计出来的结果是一个具体的值。对比区间估计&#xff0c;通过样本得出的估计值是一个范围区间。例如估计一个人的年龄&#xff0c;点估计就是最终直接估计年龄为50岁&#xff0c;而区间估计是最终估计的…

hicp学习 VRRP选举过程、MSTP+VRRP混合组网

VRRP 的选举规则 1、先比优先级&#xff0c;越大越优先&#xff0c;默认优先级是100.范围 0-255&#xff0c;可配置的范围是1-254。0和255这两个优先级是保留的不配置 0&#xff1a;用来告诉 Backup 立即成为 Master。一般是 Master 设备主动退出 VRRP 组&#xff08;人为删除…

WebKit引领潮流:CSS Container Queries深度解析

WebKit引领潮流&#xff1a;CSS Container Queries深度解析 在响应式设计的世界中&#xff0c;CSS媒体查询&#xff08;Media Queries&#xff09;一直是布局适应性的关键技术。然而&#xff0c;随着Web应用的复杂性增加&#xff0c;我们需要一种更精细的控制方式——CSS Cont…