一 redisson
1.1 redisson分布式事务
Redisson分布式锁是一种基于redis实现的分布式锁,它利用redis的setnx命令实现分布式锁的互斥访问。同时还支持锁的自动续期功能,可以避免因为某个进程崩溃或者网络故障导致锁无法释放的情况。
只要线程一加锁成功,就会启动一个watch dog看门狗,它是一个后台线程,会每隔10秒检查一下,如果线程1还持有锁,那么就会不断的延长锁key的生存时间。
因此,Redisson就是使用watch dog解决了「锁过期释放,业务没执行完」的问题。
加锁机制:
一个客户端A要加锁,它首先会根据hash节点选择一台机器,这里注意,仅仅只是选择一台机器。紧接着就会发送一段lua脚本到redis上,比如加锁的那个锁key就是"mylock",并且设置的时间是30秒,30秒后,mylock锁就会被释放。
锁互斥机制:
如果这个时候客户端B来加锁,它也会会根据hash节点选择一台机器,然后执行了同样的一段lua脚本。
它首先回来判断"exists mylock"这个锁存在吗?如果存在,则B会获得一个数字,这个数字就是mylock这个锁的剩余生存时间,此时客户端B就会进入到一个while循环,不停的尝试加锁
watch dog自动延期机制:
客户端A加锁的锁key默认生存时间只有30秒,如果超过了30秒,客户端A还想一直持有这把锁,怎么办?其实只要客户端A一旦加锁成功,就会启动一个watch dog看门狗,它是一个后台线程,会每隔10秒检查一下,如果客户端A还持有锁key,那么就会不断的延长锁key的生存时间
可重入加锁机制:
当客户端A获得mylock锁时,里面会有一个hash结构的数据:
mylock:{"8743c9c0-4907-0795-87fd-6c719a6b4586:1":1}
"8743c9c0-4907-0795-87fd-6c719a6b4586:1"就是代表客户端A,数字1就是代表这个客户端加锁了一次;如果客户端A还想要持有锁mylock,那么这个1就会变成2,依次累加
释放锁机制:
如果发现加锁次数变为0了,那么说明这个客户端不再持有锁了,客户端B就可以加锁了。
https://huaweicloud.csdn.net/637eeee1df016f70ae4c9eac.html
redisson最强大的地方就是提供了分布式特性的常用工具类。使得原本作为协调单机多线程并发程序的并发程序的工具包获得了协调分布式多级多线程并发系统的能力,降低了程序员在分布式环境下解决分布式问题的难度。
二 案例代码
2.1 工程搭建
1.工程结构
2.pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.10</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.atguigu</groupId><artifactId>distributed-lock</artifactId><version>0.0.1-SNAPSHOT</version><name>distributed-lock</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--SpringBoot与Redis整合依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency><!-- redisson 分布式锁--><dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.11.2</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.7.5</version></plugin></plugins></build></project>
2.2 redis服务启动
1.启动
2.设置
2.3 可重入锁
1.概述
2.核心代码截图
3.核心代码
@GetMapping("stock/rt")public String decuceRt(){RLock lock=this.redissonClient.getLock("my-rt");lock.lock();try {//1.查询库存信息String stock = redisTemplate.opsForValue().get("stock").toString();// 2.判断库存是否充足if (stock != null && stock.length() > 0) {Integer st = Integer.valueOf(stock);if (st > 0) {//3.减库存操作redisTemplate.opsForValue().set("stock", String.valueOf(--st));}}}finally {lock.unlock();}return "ok!!!";}
4.测试
5.查看redis
127.0.0.1:6379> get stock
"\"49\""
2.4 公平锁
1.概念
3.代码
@GetMapping("stock/fair")public String decuceFairLock(){RLock lock=this.redissonClient.getFairLock("myFairLock");lock.lock();try {//1.查询库存信息String stock = redisTemplate.opsForValue().get("stockfair").toString();// 2.判断库存是否充足if (stock != null && stock.length() > 0) {Integer st = Integer.valueOf(stock);if (st > 0) {//3.减库存操作redisTemplate.opsForValue().set("stockfair", String.valueOf(--st));}}try {TimeUnit.MILLISECONDS.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();}}finally {lock.unlock();}return "ok123!!!";}
"100"
5.查看
127.0.0.1:6379> get stockfair
"\"99\""
127.0.0.1:6379>
2.5 信号量
1.概述
@GetMapping("stock/sp")public String testsp(){RSemaphore lock=this.redissonClient.getSemaphore("sp");lock.trySetPermits(3);try {try {lock.acquire();this.redisTemplate.opsForList().rightPush("log","10086开始处理业务了"+Thread.currentThread().getName());TimeUnit.SECONDS.sleep(10+new Random().nextInt(10));this.redisTemplate.opsForList().rightPush("log","10086处理完成业务逻辑,释放资源======"+Thread.currentThread().getName());lock.release();} catch (InterruptedException e) {e.printStackTrace();}}finally {}return "信号量!!!";}
3.测试
4.查看redis
2.6 闭锁
1.概念
代码
@GetMapping("stock/suo")public String testsuo(){RCountDownLatch cd1=this.redissonClient.getCountDownLatch("cd1");cd1.trySetCount(3);System.out.println("进入 lock 之中喽。。。。。。");try {cd1.await();}catch (Exception e){e.printStackTrace();}return "cd lock!!!";}@GetMapping("stock/sf")public String testsf(){RCountDownLatch cd1=this.redissonClient.getCountDownLatch("cd1");try {cd1.countDown();System.out.println("执行 countdown---。。。。。");}catch (Exception e){e.printStackTrace();}return "cd unlock!!!";}
3.测试
这个接口请求3次,countdown变为0
这个接口才能请求完成。