redis的分布式事务-redisson

一  redisson

1.1 redisson分布式事务

Redisson分布式锁是一种基于redis实现的分布式锁,它利用redis的setnx命令实现分布式锁的互斥访问。同时还支持锁的自动续期功能,可以避免因为某个进程崩溃或者网络故障导致锁无法释放的情况。

只要线程一加锁成功,就会启动一个watch dog看门狗,它是一个后台线程,会每隔10秒检查一下,如果线程1还持有锁,那么就会不断的延长锁key的生存时间。

因此,Redisson就是使用watch dog解决了「锁过期释放,业务没执行完」问题。

redis的分布式事务-redisson_第1张图片

加锁机制:

一个客户端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.工程结构

redis的分布式事务-redisson_第2张图片

2.pom文件



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.6.10
         
    
    com.atguigu
    distributed-lock
    0.0.1-SNAPSHOT
    distributed-lock
    Demo project for Spring Boot
    
        1.8
    
    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.projectlombok
            lombok
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
        
            org.springframework.boot
            spring-boot-starter-data-redis
        
        
            org.apache.commons
            commons-pool2
        
        
        
            org.redisson
            redisson
            3.11.2
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
                2.7.5
            
        
    


2.2 redis服务启动

1.启动

redis的分布式事务-redisson_第3张图片

2.设置

redis的分布式事务-redisson_第4张图片

2.3 可重入锁

1.概述

基于 Redis Redisson 分布式可重入锁 RLock Java 对象实现了 java.util.concurrent.locks.Lock
接口。
如果负责储存这个分布式锁的 Redisson 节点宕机以后,而且这个锁正好处于锁住的状态
时,这个锁会出现锁死的状态。为了避免这种情况的发生, Redisson 内部提供了一个监控锁的看门狗, 它的作用是在Redisson 实例被关闭前,不断的延长锁的有效期。默认情况下,看门狗检查锁的超时时间是30 秒钟,也可以通过修改 Config.lockWatchdogTimeout 来另行指定。
RLock 对象完全符合 Java Lock 规范。也就是说 只有拥有锁的进程才能解锁,其他进程解锁则会抛出 IllegalMonitorStateException 错误。
另外 Redisson 还通过加锁的方法 提供了 leaseTime 的参数来指定加锁的时间 。超过这个时间后锁便自动解开了。

2.核心代码截图

redis的分布式事务-redisson_第5张图片

 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.概念

基于 Redis Redisson 分布式可重入公平锁也是实现了 java.util.concurrent.locks.Lock 接口的一
RLock 对象。
它保证了当多个Redisson 客户端线程同时请求加锁时,优先分配给先发出请求的线程。所有请求线程会在一个队列中排队,当某个线程出现宕机时,Redisson 会等待 5 秒后继续下一个线程,也就是说如果前面有 5 个线程都处于等待状态,那么后面的线程会等待至少25 秒。
2.代码
redis的分布式事务-redisson_第6张图片

 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!!!";
    }
3.设置redis
127.0.0.1:6379> get stockfair 
"100"
 
4.访问

 5.查看

127.0.0.1:6379> get stockfair 
"\"99\""
127.0.0.1:6379> 

2.5 信号量

1.概述

基于 Redis Redisson 的分布式信号量( Semaphore Java 对象 RSemaphore 采用了与
java.util.concurrent.Semaphore 相似的接口和用法。
2.代码
@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.概念

基于 Redisson Redisson 分布式闭锁( CountDownLatch Java 对象 RCountDownLatch 采用了与
java.util.concurrent.CountDownLatch 相似的接口和用法。
2.
redis的分布式事务-redisson_第7张图片

代码

@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

redis的分布式事务-redisson_第8张图片 这个接口才能请求完成。

redis的分布式事务-redisson_第9张图片

 

你可能感兴趣的:(redis,redis,分布式,数据库)