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.rhkb.cn/news/383052.html

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

相关文章

git 使用教程

注意⚠️&#xff1a;如果是公司仓库一定要注意&#xff0c;先新建自己的分支&#xff0c;修改后提交到自己分支&#xff0c;认真测试后再合并到master 一、已有远程仓库 1、配置git 的全局用户信息&#xff0c;提及时进行标识和记录 git config --global user.name "yo…

麦歌恩MT6521-第三代汽车磁性角度传感器芯片

磁性编码芯片 -在线编程角度位置IC 描述&#xff1a; MT6521是麦歌恩微电子推出的新一代基于水平霍尔及聚磁片(IMC)技术原理的磁性角度和位置检测传感器芯片。该芯片内部包含了两对互成90放置的水平霍尔阵列及聚磁片&#xff0c;能够根据不同的型号配置来实现对XY&#xff0…

外卖霸王餐系统架构怎么选?

在当今日益繁荣的外卖市场中&#xff0c;外卖霸王餐作为一种独特的营销策略&#xff0c;受到了众多商家的青睐。然而&#xff0c;要想成功实施外卖霸王餐活动&#xff0c;一个安全、稳定且高效的架构选择至关重要。本文将深入探讨外卖霸王餐架构的选择&#xff0c;以期为商家提…

linux自动化构建工具--make/makefile

目录 1.make/makefile介绍 1.1基本认识 1.2依赖关系、依赖方法 1.3具体操作步骤 1.4进一步理解 1.5默认设置 1.6make二次使用的解释 1.7两个文件的时间问题 1.8总是被执行 1.9特殊符号介绍 1.make/makefile介绍 1.1基本认识 make是一个指令&#xff0c;makefile是一…

【C++BFS算法】2192. 有向无环图中一个节点的所有祖先

本文涉及知识点 CBFS算法 LeetCode2192. 有向无环图中一个节点的所有祖先 给你一个正整数 n &#xff0c;它表示一个 有向无环图 中节点的数目&#xff0c;节点编号为 0 到 n - 1 &#xff08;包括两者&#xff09;。 给你一个二维整数数组 edges &#xff0c;其中 edges[i]…

MQ传递用户信息

theme: nico 你们好&#xff0c;我是金金金。 场景 购物车里面有5个商品&#xff0c;用户勾选了并且提交订单了&#xff0c;此时需要删除购物车对应勾选的商品&#xff0c;mq的话涉及到传递用户信息~因为删除对应的购物车商品是需要传递用户信息来知晓对应用户的 生产者 消费者…

2022真题-架构师案例(二)

1、某大型电商平台建立了一个在线B2B商店系统&#xff0c;并在全匡多地建设了货物仓储中心&#xff0c;通过提前备货的方式来提高货物的运送效率。但是在运营过程中&#xff0c;发现会出现很多跨仓储中心调货从而延误货物运送的情况。为此&#xff0c;该企业计划新建立一个全国…

Pytorch 6

罗切斯特回归模型 加了激活函数 加了激活函数之后类 class LogisticRegressionModel(torch.nn.Module):def __init__(self):super(LogisticRegressionModel, self).__init__()self.linear torch.nn.Linear(1,1)def forward(self, x):# y_pred F.sigmoid(self.linear(x))y_p…

Python 教程(二):语法与数据结构

目录 前言专栏列表语法特点实例代码基本数据类型变量命名规则赋值动态类型作用域示例代码 运算符list、set和dict 数据结构 区别1. list&#xff08;列表&#xff09;2. set&#xff08;集合&#xff09;3. dict&#xff08;字典&#xff09; 总结 前言 Python 是一种计算机编…

虚拟机OP的LAN网口设置

问题&#xff1a;unraid通过虚拟机安装OP&#xff0c;然而一个网口连接路由器&#xff0c;总是无法为其他设备提供DHCP&#xff0c;导致无法使用。 一、虚拟机OP配置 二、OP内部配置 对于Lan网口&#xff0c;启用强制&#xff0c;这样可以防止OP被网口接的路由器产生冲突 三、…

第八讲 视觉里程计2

不提取特征点计算VO&#xff1a; 一是通过其他方式寻找配对点&#xff08;光流法&#xff0c;跟踪特征点的运动&#xff09;&#xff0c;仍然使用特征点&#xff0c;只是把匹配描述子替换成了光流跟踪&#xff0c;估计相机运动仍使用对极几何、PnP或ICP算法。依然要求提取到的关…

CefSharp音视频编译与免费下载

注&#xff1a;Cefharp 音频和视频播放编译&#xff0c;生成相应的dll文件&#xff0c;从而支持项目开发。 建议编译至少 16G 的 RAM和至少 250G 的 SSD。该脚本以 E 盘为例&#xff0c;您需要在 E 盘上手动创建 cef 文件夹。禁止在转载后通过发布其他平台向用户收取下载费用。…

TypeScript中Interface接口的深度探索与实践

定义接口 在TypeScript中&#xff0c;interface是一个强有力的概念&#xff0c;它用于定义类型签名&#xff0c;特别是对象的结构。接口可以用来描述对象应该有哪些属性、方法&#xff0c;以及这些成员的类型。它们是实现类型系统中“鸭子类型”&#xff08;duck typing&#…

vue3实现在新标签中打开指定的网址

有一个文件列表&#xff0c;如下图&#xff1a; 我希望点击查看按钮的时候&#xff0c;能够在新的标签页面打开这个文件的地址进行预览&#xff0c;该如何实现呢&#xff1f; 比如&#xff1a; 实际上要实现这个并不难&#xff0c;参考demo如下&#xff1a; 首先&#x…

网络安全等级保护解决方案的主打产品

网络安全等级保护解决方案的主打产品&#xff1a; HiSec Insight安全态势感知系统、 FireHunter6000沙箱、 SecoManager安全控制器、 HiSecEngine USG系列防火墙和HiSecEngine AntiDDoS防御系统。 华为HiSec Insight安全态势感知系统是基于商用大数据平台FusionInsight的A…

浅谈C语言整型类数据在内存中的存储

1、整型类数据 C语言中的整型类数据都归类在整型家族中&#xff0c;其中包括&#xff1a;char、short、int、long、long long这5个大类&#xff0c;而每个大类中又分为两类signed和unsigned,这些都是C语言中的内置类型。以下重点基于char和int这两种类型的数据进行阐述&#x…

dsa加训

refs: OI Wiki - OI Wiki (oi-wiki.org) 1. 枚举 POJ 2811 熄灯问题 refs : OpenJudge - 2811:熄灯问题 如果要枚举每个灯开或者不开的情况&#xff0c;总计2^30种情况&#xff0c;显然T。 不过我们可以发现&#xff1a;若第i行的某个灯亮了&#xff0c;那么有且仅有第i行和第…

springcloud接入skywalking作为应用监控

下载安装包 需要下载SkyWalking APM 和 Java Agent 链接: skywalking 安装 下载JDK17&#xff08;可不配置环境变量&#xff09; 目前skywalking 9.0及以上版本基本都不支持JDK8&#xff0c;需要JDK11-21&#xff0c;具体版本要求在官网查看。 我这里使用的是skywalking9.…

德国云手机:企业移动办公解决方案

在现代商业环境中&#xff0c;移动办公已经成为一种趋势。德国云手机作为一种高效的解决方案&#xff0c;为企业提供了强大的支持。本文将探讨德国云手机如何优化企业的移动办公环境。 一、德国云手机的主要优势 高灵活性 德国云手机具有高度的灵活性&#xff0c;能够根据用户需…

链式法则和自动求导

向量链式法则 说明&#xff1a; 1.第一个式子&#xff0c; y是标量&#xff0c;u是标量&#xff0c;x是n维向量 2.第二个式子&#xff0c;y是标量&#xff0c;u是k维向量&#xff0c;x是n维向量&#xff0c;所以y对u求导是k维的行向量&#xff0c;u对x求导是k行n列的矩阵&…