微服务系列文章之 Redisson实现分布式锁(3)

一、概述

1、技术架构

项目总体技术选型

SpringBoot2.4.5 + Maven3.5.4 + Redisson3.5.4 + lombok(插件)

2、加锁方式

该项目支持 自定义注解加锁 和 常规加锁 两种模式

自定义注解加锁

 @DistributedLock(value="goods", leaseTime=5)public String lockDecreaseStock(){//业务逻辑}

常规加锁

 //1、加锁redissonLock.lock("redisson", 10);//2、业务逻辑//3、解锁redissonLock.unlock("redisson");

3、Redis部署方式

该项目支持四种Redis部署方式

1、单机模式部署
2、集群模式部署
3、主从模式部署
4、哨兵模式部署

该项目已经实现支持上面四种模式,你要采用哪种只需要修改配置文件application.properties,项目代码不需要做任何修改。

4、项目整体结构

redis-distributed-lock-core # 核心实现
|
---src|---com.jincou.redisson|# 通过注解方式 实现分布式锁---annotation|# 配置类实例化RedissonLock---config|# 放置常量信息---constant|# 读取application.properties信息后,封装到实体---entity    |# 支持单机、集群、主从、哨兵 代码实现---strategyredis-distributed-lock-web-test # 针对上面实现类的测试类
|
---src|---java|---com.jincou.controller|# 测试 基于注解方式实现分布式锁---AnnotatinLockController.java|# 测试 基于常规方式实现分布式锁---LockController.java---resources                | # 配置端口号 连接redis信息(如果确定部署类型,那么将连接信息放到core项目中)---application.properties

二、测试

模拟1秒内100个线程请求接口,来测试结果是否正确。同时测试3中不同的锁:lock锁、trylock锁、注解锁。

1、lock锁

  /*** 模拟这个是商品库存*/public static volatile Integer TOTAL = 10;@GetMapping("lock-decrease-stock")public String lockDecreaseStock() throws InterruptedException {redissonLock.lock("lock", 10);if (TOTAL > 0) {TOTAL--;}Thread.sleep(50);log.info("======减完库存后,当前库存===" + TOTAL);//如果该线程还持有该锁,那么释放该锁。如果该线程不持有该锁,说明该线程的锁已到过期时间,自动释放锁if (redissonLock.isHeldByCurrentThread("lock")) {redissonLock.unlock("lock");}return "=================================";}

压测结果

没问题,不会超卖!

2、tryLock锁

 /*** 模拟这个是商品库存*/public static volatile Integer TOTAL = 10;@GetMapping("trylock-decrease-stock")public String trylockDecreaseStock() throws InterruptedException {if (redissonLock.tryLock("trylock", 10, 5)) {if (TOTAL > 0) {TOTAL--;}Thread.sleep(50);redissonLock.unlock("trylock");log.info("====tryLock===减完库存后,当前库存===" + TOTAL);} else {log.info("[ExecutorRedisson]获取锁失败");}return "===================================";}

测试结果

没有问题 ,不会超卖!

3、注解锁

/*** 模拟这个是商品库存*/public static volatile Integer TOTAL = 10;@GetMapping("annotatin-lock-decrease-stock")@DistributedLock(value="goods", leaseTime=5)public String lockDecreaseStock() throws InterruptedException {if (TOTAL > 0) {TOTAL--;}log.info("===注解模式=== 减完库存后,当前库存===" + TOTAL);return "=================================";}

测试结果

没有问题 ,不会超卖!

通过实验可以看出,通过这三种模式都可以实现分布式锁,然后呢?哪个最优。

三、三种锁的锁选择

观点 最完美的就是lock锁,因为

1、tryLock锁是可能会跳过减库存的操作,因为当过了等待时间还没有获取锁,就会返回false,这显然很致命!2、注解锁只能用于方法上,颗粒度太大,满足不了方法内加锁。

1、lock PK tryLock 性能的比较

模拟5秒内1000个线程分别去压测这两个接口,看报告结果!

1)lock锁

压测结果 1000个线程平均响应时间为31324。吞吐量 14.7/sec

2)tryLock锁

压测结果 1000个线程平均响应时间为28628。吞吐量 16.1/sec

这里只是单次测试,有很大的随机性。从当前环境单次测试来看,tryLock稍微高点。

2、常见异常 attempt to unlock lock, not ······

在使用RedissonLock锁时,很容易报这类异常,比如如下操作

   //设置锁1秒过去redissonLock.lock("redisson", 1);/*** 业务逻辑需要咨询2秒*/redissonLock.release("redisson");

上面在并发情况下就会这样

造成异常原因:

线程1 进来获得锁后,但它的业务逻辑需要执行2秒,在 线程1 执行1秒后,这个锁就自动过期了,那么这个时候 
线程2 进来了获得了锁。在线程1去解锁就会抛上面这个异常(因为解锁和当前锁已经不是同一线程了)

所以我们需要注意,设置锁的过期时间不能设置太小,一定要合理,宁愿设置大点。

正对上面的异常,可以通过isHeldByCurrentThread()方法,

  //如果为false就说明该线程的锁已经自动释放,无需解锁if (redissonLock.isHeldByCurrentThread("lock")) {redissonLock.unlock("lock");}

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

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

相关文章

8、链路层以太网协议,ARP协议32

网络层IP协议描述了通信中的起点到终点,但是数据不是飞过去的,是经过了大量的中间节点转发完成的。 一、以太网协议 1、MAC地址 物理硬件地址,是每一块网卡在出厂时设定的地址,固定且不可修改(早期,现在可…

C语言模拟实现字符串处理函数

需要多一点点勇气,来面对变差的自己 大家好,我是纪宁。 这篇文章为大家带来的是5大字符串处理函数的模拟实现。 文章目录 1.strlen函数的模拟实现 2.strcpy函数的模拟实现 3.strcmp函数的模拟实现 4.strcat函数的模拟实现 5.strstr函数的模拟实现…

软件测试|SQL常用语法,你都会吗?

前言 SQL作为一门语言,和其他编程语言一样,都是需要遵循一些特定的规范和准则的,这也就是我们常说的语法(Syntax)。 下面是几个SQL的语法规则: 所有的 SQL 语法都必须以关键字(也称命令&…

04-spring配置文件加载过程

文章目录 spring配置文件加载过程 spring配置文件加载过程 调用refresh方法中obtainFreshBeanFactory() Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.…

我们如何在 Elasticsearch 8.6、8.7 和 8.8 中加速数据摄入

作者:Adrien Grand, Joe Gallo, Tyler Perkins 正如你们中的一些人已经注意到的,Elasticsearch 8.6、8.7 和 8.8 在各种数据集上带来了良好的索引加速,从简单的关键字到繁重的 KNN 向量,以及摄取管道繁重的摄取工作负载。 摄取涉及…

推荐10个Flutter开源项目

作为跨平台应用开发的领头羊,Flutter从已发布就受到广大开发者的追捧。使用Flutter技术开发的应用不仅体验上无限接近原生应用,在开发效率上也是其他技术无法比拟的。随着其开发者社区的不断壮大,Flutter生态系统已经相当强大,并且众多开源应用程序也相继诞生。这些开源应用…

ceph--cephFS的使用

ceph分布式存储—cephFS的使用 1、cephfs的概念 ceph FS 即 ceph filesystem,可以实现文件系统共享功能,客户端通过 ceph 协议挂载并使 用 ceph 集群作为数据存储服务器。 Ceph FS 需要运行 Meta Data Services(MDS)服务,其守护进程为 ceph-mds&#x…

MongoDB

安装 数据存放路径:D:\data\db 安装目录:D:\MongoDB\mongodb-windows-x86_64-5.0.19\mongodb-win32-x86_64-windows-5.0.19\bin 配置环境变量 开启服务端,客户端 # 开启服务端,指定数据存放路径 mongod --dbpath D:\data\…

【HCIA】11.ACL与NAT地址转换

ACL 通过ACL可以实现对网络中报文流的精确识别和控制,达到控制网络访问行为、防止网络攻击和提高网络带宽利用率的目的。 ACL是由permit或deny语句组成的一系列有顺序的规则的集合;它通过匹配报文的相关字段实现对报文的分类。ACL是能够匹配一个IP数据包…

vue 通过多组复选框来过滤数据

1.通过if else 来筛选数据 <template> <div><div><label><input type"checkbox" v-model"checkedNames" value"北京"> 北京</label><label><input type"checkbox" v-model"chec…

【Web UI自动化测试】Web UI自动化测试之框架篇(全网最全)

本文大纲截图&#xff1a; UnitTest框架&#xff1a; PyTest框架&#xff1a; 框架&#xff1a; 框架英文单词 framework&#xff0c;为解决一类事情的功能的集合。需要按照框架的规定&#xff08;套路&#xff09;去书写代码。 一、UnitTest框架介绍【文末分享自动化测试学习…

【iOS】—— 编译链接

【iOS】—— 编译链接 文章目录 【iOS】—— 编译链接编译流程预处理&#xff08;预编译Prepressing&#xff09;编译&#xff08;Compilation&#xff09;汇编&#xff08;Assembly&#xff09;链接&#xff08;Linking&#xff09; 编译流程 编译流程分为四步 预处理&#…