RedLock + Redisson
目录
- 2.9 RedLock
- 2.9.1 上述实现的分布式锁在集群状态下失效的原因
- 2.9.2 解决方式-RedLock
- 2.10 ==redisson中的分布式锁==
- 2.10.0 redisson简介以及简单使用
- 简单使用redisson中的锁
- Redisson常用配置
- 2.10.1 Redisson可重入锁实现原理
- 2.10.2 公平锁(Fair Lock)
- 2.10.3 联锁(MultiLock) (没用 !!!!)
- 2.10.4 红锁(RedLock)
- 2.10.5 读写锁(ReadWriteLock)
- 2.10.6 ==信号量(Semaphore)==
- 2.10.7 ==闭锁==(CountDownLatch)
2.9 RedLock
2.9.1 上述实现的分布式锁在集群状态下失效的原因
redis集群状态下的问题:
- 客户端A从master获取到锁
- 在master将锁同步到slave之前,master宕掉了。
- slave节点被晋级为master节点
- 客户端B取得了同一个资源被客户端A已经获取到的另外一个锁。
2.9.2 解决方式-RedLock
解决集群下锁失效,参照redis官方网站针对redlock文档:https://redis.io/topics/distlock
加锁算法
2.10 redisson中的分布式锁
2.10.0 redisson简介以及简单使用
Redisson提供了一系列的分布式的Java常用对象,还提供了许多分布式服务。其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service)
Redisson提供了使用Redis的最简单和最便捷的方法。Redisson的宗旨是促进使用者对Redis的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上。
官方文档地址:https://github.com/redisson/redisson/wiki
简单使用redisson中的锁
注入 RedissonClient 客户端
@Configuration
public class RedissonConfig {@Beanpublic RedissonClient redissonClient() {// 默认连接地址 127.0.0.1:6379Config config = new Config();config.useSingleServer().setAddress("redis://121.40.182.123:6379").setPassword("houchen");RedissonClient redisson = Redisson.create(config);return redisson;}
}
使用 RedisClient的锁。StockService 代码片段如下
public void deduct() {RLock lock = redissonClient.getLock("lock");lock.lock();try {String stockStr = redisTemplate.opsForValue().get("stock:" + "1001");// 2. 判断库存是否充足if (stockStr != null && stockStr.length() != 0) {Long stock = Long.parseLong(stockStr);if (stock > 0) {redisTemplate.opsForValue().set("stock:" + "1001", String.valueOf(stock - 1));}}} finally {lock.unlock();}}
使用 Jmeter并发压测后,查看redis的库存确实减为0,表明redisson锁是确实是可用的
Redisson常用配置
2.10.1 Redisson可重入锁实现原理
之后进行补充
可重入锁演示测试
public void deduct() {RLock lock = redissonClient.getLock("lock");lock.lock();try {String stockStr = redisTemplate.opsForValue().get("stock:" + "1001");// 2. 判断库存是否充足if (stockStr != null && stockStr.length() != 0) {Long stock = Long.parseLong(stockStr);if (stock > 0) {redisTemplate.opsForValue().set("stock:" + "1001", String.valueOf(stock - 1));}}this.test1();} finally {lock.unlock();}}private void test1() {RLock lock = redissonClient.getLock("lock");lock.lock();System.out.println("获取到可重入锁");System.out.println("执行其他业务代码......");lock.unlock();}
由演示结果可以得出结论,RLock 是可重入锁!!
2.10.2 公平锁(Fair Lock)
基于Redis的Redisson分布式可重入公平锁也是实现了java.util.concurrent.locks.Lock
接口的一种RLock
对象。它保证了当多个Redisson客户端线程同时请求加锁时,优先分配给先发出请求的线程。所有请求线程会在一个队列中排队,当某个线程出现宕机时,Redisson会等待5秒后继续下一个线程,也就是说如果前面有5个线程都处于等待状态,那么后面的线程会等待至少25秒。
RLock fairLock = redisson.getFairLock("anyLock");
// 最常见的使用方法
fairLock.lock();// 10秒钟以后自动解锁
// 无需调用unlock方法手动解锁
fairLock.lock(10, TimeUnit.SECONDS);// 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
boolean res = fairLock.tryLock(100, 10, TimeUnit.SECONDS);
fairLock.unlock();
2.10.3 联锁(MultiLock) (没用 !!!!)
基于Redis的Redisson分布式联锁RedissonMultiLock对象可以将多个RLock
对象关联为一个联锁,每个RLock
对象实例可以来自于不同的Redisson实例。
RLock lock1 = redissonInstance1.getLock("lock1");
RLock lock2 = redissonInstance2.getLock("lock2");
RLock lock3 = redissonInstance3.getLock("lock3");RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3);
// 同时加锁:lock1 lock2 lock3
// 所有的锁都上锁成功才算成功。
lock.lock();
...
lock.unlock();
2.10.4 红锁(RedLock)
基于Redis的Redisson红锁RedissonRedLock
对象实现了 2.9 RedLock 介绍的加锁算法。该对象也可以用来将多个RLock
对象关联为一个红锁,每个RLock
对象实例可以来自于不同的Redisson实例。
RLock lock1 = redissonInstance1.getLock("lock1");
RLock lock2 = redissonInstance2.getLock("lock2");
RLock lock3 = redissonInstance3.getLock("lock3");RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
// 同时加锁:lock1 lock2 lock3
// 红锁在大部分节点上加锁成功就算成功。
lock.lock();
...
lock.unlock();
2.10.5 读写锁(ReadWriteLock)
基于Redis的Redisson分布式可重入读写锁RReadWriteLock
Java对象实现了java.util.concurrent.locks.ReadWriteLock
接口。其中读锁和写锁都继承了RLock接口。
分布式可重入读写锁允许同时有多个读锁和一个写锁处于加锁状态。
RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock");
// 最常见的使用方法
rwlock.readLock().lock();
// 或
rwlock.writeLock().lock();// 10秒钟以后自动解锁
// 无需调用unlock方法手动解锁
rwlock.readLock().lock(10, TimeUnit.SECONDS);
// 或
rwlock.writeLock().lock(10, TimeUnit.SECONDS);// 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
boolean res = rwlock.readLock().tryLock(100, 10, TimeUnit.SECONDS);
// 或
boolean res = rwlock.writeLock().tryLock(100, 10, TimeUnit.SECONDS);
...
lock.unlock();
添加StockController方法:
@GetMapping("test/read")
public String testRead(){String msg = stockService.testRead();return "测试读";
}@GetMapping("test/write")
public String testWrite(){String msg = stockService.testWrite();return "测试写";
}
添加StockService方法:
public String testRead() {RReadWriteLock rwLock = this.redissonClient.getReadWriteLock("rwLock");rwLock.readLock().lock(10, TimeUnit.SECONDS);System.out.println("测试读锁。。。。");// rwLock.readLock().unlock();return null;
}public String testWrite() {RReadWriteLock rwLock = this.redissonClient.getReadWriteLock("rwLock");rwLock.writeLock().lock(10, TimeUnit.SECONDS);System.out.println("测试写锁。。。。");// rwLock.writeLock().unlock();return null;
}
- 同时访问写:一个写完之后,等待一会儿(约10s),另一个写开始
- 同时访问读:不用等待
- 先写后读:读要等待(约10s)写完成
- 先读后写:写要等待(约10s)读完成
2.10.6 信号量(Semaphore)
JUC Semaphore的小小演示:
public static void main(String[] args) {Semaphore semaphore = new Semaphore(3);for (int i = 0; i < 5; i++) {new Thread(() -> {try {semaphore.acquire(1);System.out.println(Thread.currentThread().getName() + "获取到停车位");TimeUnit.SECONDS.sleep(new Random().nextInt(10));System.out.println(Thread.currentThread().getName() + "将车开走了!!!");semaphore.release();} catch (InterruptedException e) {throw new RuntimeException(e);}}, i + "号车").start();}}
可以看到任意一个时刻,最多只有三辆车能获取到停车位
基于Redis的Redisson的分布式信号量(Semaphore)Java对象RSemaphore
采用了与java.util.concurrent.Semaphore
相似的接口和用法。同时还提供了异步(Async)、反射式(Reactive)和RxJava2标准的接口。
在StockController添加方法:
@GetMapping("test/semaphore")
public String testSemaphore(){this.stockService.testSemaphore();return "测试信号量";
}
在StockService添加方法:
public void testSemaphore() {RSemaphore semaphore = this.redissonClient.getSemaphore("semaphore");semaphore.trySetPermits(3);try {semaphore.acquire();System.out.println(Thread.currentThread().getName() + "获取了信号量资源,开始执行业务逻辑,----------> start");TimeUnit.SECONDS.sleep(new Random().nextInt(10));System.out.println(Thread.currentThread().getName() + "获取执行完了业务逻辑,释放信号量资源,----------> end");semaphore.release();} catch (InterruptedException e) {e.printStackTrace();}}
2.10.7 闭锁(CountDownLatch)
JUC CountDownLatch使用demo
CountDownLatch 适用于一个线程等待一组线程的执行完成!!!!
public static void main(String[] args) throws InterruptedException {CountDownLatch countDownLatch= new CountDownLatch(5);for (int i = 0; i < 5; i++) {new Thread(() -> {try {System.out.println(Thread.currentThread().getName() + "---> 准备出门了");TimeUnit.SECONDS.sleep(new Random().nextInt(10));System.out.println(Thread.currentThread().getName() + "---> 真真切切出门了.....");countDownLatch.countDown();} catch (InterruptedException e) {throw new RuntimeException(e);}}, i + "同学").start();}countDownLatch.await();System.out.println("班长关门了...");
基于Redisson的Redisson分布式闭锁CountDownLatch对象RCountDownLatch
采用了与java.util.concurrent.CountDownLatch
相似的接口和用法。
RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
latch.trySetCount(1);
latch.await();// 在其他线程或其他JVM里
RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
latch.countDown();
需要两个方法:一个等待,一个计数countDown
给StockController添加测试方法:
@GetMapping("test/latch")
public String testLatch(){this.stockService.testLatch();return "班长锁门。。。";
}@GetMapping("test/countdown")
public String testCountDown(){this.stockService.testCountDown();return "出来了一位同学";
}
给StockService添加测试方法:
public void testLatch() {RCountDownLatch latch = this.redissonClient.getCountDownLatch("latch");latch.trySetCount(6);try {latch.await();} catch (InterruptedException e) {e.printStackTrace();}
}public void testCountDown() {RCountDownLatch latch = this.redissonClient.getCountDownLatch("latch");latch.trySetCount(6);latch.countDown();
}
重启测试,打开两个页面:当第二个请求执行6次之后,第一个请求才会执行。
相关文章:

RedLock + Redisson
目录 2.9 RedLock2.9.1 上述实现的分布式锁在集群状态下失效的原因2.9.2 解决方式-RedLock 2.10 redisson中的分布式锁2.10.0 redisson简介以及简单使用简单使用redisson中的锁Redisson常用配置 2.10.1 Redisson可重入锁实现原理2.10.2 公平锁(Fair Lock)…...

计算机视觉:卷积层的参数量是多少?
本文重点 卷积核的参数量是卷积神经网络中一个重要的概念,它决定了网络的复杂度和计算量。在深度学习中,卷积操作是一种常用的操作,用于提取图像、语音等数据中的特征。卷积神经网络的优势点在于稀疏连接和权值共享,这使得卷积核的参数相较于传统的神经网络要少很多。 举例…...

Docker 容器基础操作
Docker容器基础操作 容器(container)是Docker镜像的运行实例,类似于可执行文件与进程的关系,Docker是容器引擎,相当于系统平台。 容器的生命周期 容器的基础操作(以 tomcat8.0 为例) # 拉取tomcat8.0镜像 [root@tudou tudou]# docker pull tomcat:8.0 8.0: Pulling f…...

【Vue3+Ts+Vite】配置滚动条样式
一、先看效果 二、直接上代码 <template><div class"main-container"><h1 v-for"index in 50" :key"index">这是home页面</h1></div> </template> <style lang"scss" scoped> .main-conta…...
react map使用方法详解
在React中,map()方法是用于数组的常见方法之一,它可以用于处理数组并返回一个新的数组。在React中,经常使用map()方法来遍历数组,生成对应的组件列表或进行数据转换操作。 下面是map()方法在React中的使用方法详解: …...

PoseiSwap:通过 RWA 的全新叙事,反哺 Nautilus Chain 生态
PoseiSwap 是 Nautilus Chain 上的首个 DEX,作为目前行业内模块化区块链叙事的早期奉行者,PoseiSwap 也得到了较高的市场关注。基于 Nautilus Chain,PoseiSwap 打造了一个全新的 Rollup 应用层,并通过零知识证明来建立全新的订单簿…...

PHP8的常量-PHP8知识详解
常量和变量是构成PHP程序的基础,在PHP8中常量的这一节中,主要讲到了定义常量和预定义常量两大知识点。 一、定义常量 定义常量也叫声明常量。在PHP8中,常量就是一个标识符(名字),一旦定义(声明&…...
印花税的本质和底层逻辑是什么?印花税降低是利好股市吗?
内容由LLM协助生成: 印花税是一种对特定交易或证券交易征收的税费,由政府机构收取。其本质和底层逻辑可以归结为以下几点: 资金来源:印花税是国家财政收入的一部分,用于满足政府的财政需求和公共支出。政府通过征收印花…...
pytorch+GPU跑模型时 nvrtc: error: failed to open nvrtc-builtins64_117.dll
1.先检查自己cuda版本: print(torch.version.cuda) #查看cuda版本 print(torch.cuda.is_available()) # 查看cuda是否可用 print(torch.cuda.device_count()) # 查看可行的cuda数目如果版本高于11建议先降版本,然后再试下。 2.重新安装nvrtc-builtin…...

SQL-每日一题【626.换座位】
题目 表: Seat 编写SQL查询来交换每两个连续的学生的座位号。如果学生的数量是奇数,则最后一个学生的id不交换。 按 id 升序 返回结果表。 查询结果格式如下所示。 示例 1: 解题思路 前置知识 MySQL 的 MOD() 函数是取模运算的函数,它返回两个数相除…...

Swagger之Hello World !
目录 ■1.前言・Swagger介绍 ■2.例子,如果基于Spring Boot项目,实现Swagger---非常简单 2.1.已有的SpringBoot项目 2.2.修改POM文件 2.3.添加Config文件…...

VSCode SSH远程连接与删除
1.ubuntu设置 安装SSH服务并获取远程访问的IP地址 在Ubuntu系统中,“CtrlAltT”打开终端工具,执行如下命令安装SSH服务。 sudo apt-get install openssh-server如果安装失败则先安装依赖项。 2.VS Code 设置 2.1安装与设置Remote SSH 打开Windows系…...

面试典中典之线程池的七大参数
文章目录 一、七大元素解释1.corePoolSize(核心线程数):2.maximumPoolSize(最大线程数):3.keepAliveTime(线程空闲时间):4.unit(时间单位)&#x…...

Maven如何创建Java web项目(纯干货版)!!!
1.创建Maven项目。 2.创建完成后会来到这个界面。 3.在src/main目录下,建立webapp / WEB-INF/web.xml文件,并在web.xml文件中写入以下内容: <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns"http…...
linux进程间通信的方式及特点
1:信号 描述: 信号是linux上的一种软中断通信机制,可以向指定进程发送通知,总共有64种信号; 特点: 信号只能作为通知使用,没办法传递数据; 2:socket套接字 描述&#…...
京东的成功秘诀:找到自己独特而有效的商业模式
你知道京东为什么能够从一个卖电器的小网站发展成为中国最大的电商平台吗?如果京东一开始靠卖电器赚钱,不可能有今天,在十几年刘强东刚创业的时候,如果京东靠卖电器赚钱,你知道想当年的国美黄光裕和想当年的苏宁的张近…...

全局ip代理安全吗? 手机设置全局代理方法详解
全局IP代理并不一定是安全的,因为全局IP代理会将所有网络流量都通过代理服务器进行转发,包括敏感信息和隐私数据。如果代理服务器受到黑客攻击或存在安全漏洞,可能会导致数据泄露和其他安全问题。因此,在使用全局IP代理时…...
Clion开发Stm32之温湿度传感器(DHT11)驱动编写
前言 涵盖之前文章: Clion开发STM32之HAL库GPIO宏定义封装(最新版)Clion开发stm32之微妙延迟(采用nop指令实现)Clion开发STM32之日志模块(参考RT-Thread) DHT11驱动文件 头文件 /*******************************************************************************Copyrig…...
位操作相关的函数(C++)
目录 popcount函数 bitset类模板 __builtin_popcount函数 popcount函数 在C中,std::popcount函数是用来计算一个整数二进制表示中包含的1的个数。不过要注意,这个函数是C20标准引入的,因此在使用之前,要先确保编译器支持C20标…...

arm 函数栈回溯
大概意思就是arm每个函数开始都会将PC、LR、SP以及FP四个寄存器入栈。 下面我们看一下这四个寄存器里面保存的是什么内存 arm-linux-gnueabi-gcc unwind.c -mapcs -w -g -o unwind(需要加上-mapcs才会严格按照上面说的入栈) #include <stdio.h> …...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...

多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...

毫米波雷达基础理论(3D+4D)
3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文: 一文入门汽车毫米波雷达基本原理 :https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...
django blank 与 null的区别
1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是,要注意以下几点: Django的表单验证与null无关:null参数控制的是数据库层面字段是否可以为NULL,而blank参数控制的是Django表单验证时字…...