• redisson分布式锁实验(读写锁&&重入锁)


    在idea中新建一个springboot项目

    在这里插入图片描述

    添加redisson相关依赖

    在pom.xml中添加依赖:
    其中redisson-spring-boot-starter是redisson相关依赖,spring-boot-starter-data-redis是和redis相关的依赖

    
        org.redisson
        redisson-spring-boot-starter
        3.17.5
    
    
        org.springframework.boot
        spring-boot-starter-data-redis
        
            
                io.lettuce
                lettuce-core
            
        
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    配置redisson

    在跟目录下新建一个config包,在config包里面添加一个配置类:RedissonConfig,java
    在这里插入图片描述
    RedissonConfig,java代码:
    @Configuration指定该类为配置类,其中@bean声明了一个redissonClient,将其注册到springboot框架中去
    这种做法与spring中xml配置取得的效果是一样的,就可以把配置类理解为spring中的xml文件

    package com.example.demo.config;
    
    import org.redisson.Redisson;
    import org.redisson.api.RedissonClient;
    import org.redisson.config.Config;
    import org.redisson.config.SingleServerConfig;
    import org.redisson.config.TransportMode;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class RedissonConfig {
    
        @Bean
        public RedissonClient redissonClient(){
            Config config = new Config();
            config.setTransportMode(TransportMode.NIO);
            SingleServerConfig singleServerConfig = config.useSingleServer();
    
    		//这一步设置redis的地址
            singleServerConfig.setAddress("redis://127.0.0.1:6379");
            //设置redis的密码
            singleServerConfig.setPassword("123456");
            RedissonClient redisson = Redisson.create(config);
            return redisson;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    读写锁

    这样就得到一个redissonClient对象了,下面新建一个cotroller包,并建立一个cotroller对象进行实验:
    在这里插入图片描述
    TestController代码:

    package com.example.demo.controller;
    
    import org.redisson.api.RLock;
    import org.redisson.api.RReadWriteLock;
    import org.redisson.api.RedissonClient;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.UUID;
    
    @RestController
    public class TestController {
    
        @Autowired
        StringRedisTemplate redisTemplate;
        @Autowired
        private RedissonClient redissonClient;
    
        @GetMapping("read")
        public String read(){
            RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("lockname");
            RLock rLock = readWriteLock.readLock();
            try {
                rLock.lock();
                String uuid = redisTemplate.opsForValue().get("uuid");
                return uuid;
            }finally {
                rLock.unlock();
            }
        }
    
        @GetMapping("write")
        public String write() throws InterruptedException {
            RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("lockname");
            //写之前加写锁,写锁加锁成功,读锁只能等待
            RLock rLock = readWriteLock.writeLock();
            String s = "";
            try {
                rLock.lock();
                s = UUID.randomUUID().toString();
                Thread.sleep(10000);
                redisTemplate.opsForValue().set("uuid",s);
            }finally {
                rLock.unlock();
            }
            return s;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    这里AutoWired装填了两个对象:
    redisTemplate是redis连接,具体的配置,在application.properties中进行设置,一般springboot建立的时候就已经自动生成了:
    redissonClient是配置类里定义的bean
    在这里插入图片描述
    application.yml代码:

    spring:
      redis:
        host: 127.0.0.1
        port: 6379
        password: "123456"
    
    server:
      port: 8080
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    读写锁实验

    这里分别设置application.yml中的server.port=8080和8081,同时在两个端口运行springboot:
    左上角可以看到开了两个进程:
    在这里插入图片描述
    如果不行的话,可能需要设置一下“允许多个实例”:
    在这里插入图片描述
    在“修改选项”中选择“允许多个实例”
    在这里插入图片描述

    读写锁的逻辑是“读读不互斥,读写互斥和写写互斥”:

    1.读读不互斥:
    这里分别访问两个地址的read请求,都能得到结果
    在这里插入图片描述
    2.读写互斥:
    先访问8080端口的write,再访问8081端口的read,代码里面设置了10秒钟延时模拟写的过程:
    所以在write进程在运行时,read是阻塞的,等write进程运行完成,read得到结果
    3.写写互斥:
    启动两个写请求,后写的请求会等待先写的请求结束后才能写

    重入锁

    TestController代码:

    package com.example.demo.controller;
    
    import org.redisson.api.RLock;
    import org.redisson.api.RReadWriteLock;
    import org.redisson.api.RedissonClient;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.UUID;
    
    @RestController
    public class TestController {
    
        @Autowired
        StringRedisTemplate redisTemplate;
        @Autowired
        private RedissonClient redissonClient;
    
        @RequestMapping("/buy")
        public String deductProduct()
        {
            RLock redissonLock = redissonClient.getLock("productKey");
            redissonLock.lock();
            int product = Integer.parseInt(redisTemplate.opsForValue().get("product"));
            if(product > 0){
                int realProduct = product - 1;
                redisTemplate.opsForValue().set("product", realProduct + "");
                System.out.println("购买成功,剩余产品数量:" + realProduct);
            }
            else {
                System.out.println("购买失败,库存不足");
            }
    
            redissonLock.unlock();
            return "end";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    这里需要在redis里面设置一个product变量,表示产品的数量,可以使用redisclient图形化界面进行设置,也可以通过redis命令进行设置:
    在这里插入图片描述

    压力测试和负载均衡

    1.压力测试:
    网上下载apache jmeter工具进行压力测试:
    在这里插入图片描述
    在这里插入图片描述
    (1)thread group:
    number of threads:线程请求个数
    ramp-up period:在多长时间内将规定的线程请求发送出去
    loop count:进行轮数
    在这里插入图片描述
    (2)http:request:
    在这里插入图片描述
    (3)aggressive report:设置日志

    2.nginx设置负载均衡:
    具体设置是在nginx.conf里面设置,将请求分摊到8080和8081两个端口实现负载均衡:
    在这里插入图片描述

    在这里插入图片描述

    可重入锁实验

    为什么要设置负载均衡?
    因为要模拟高并发的场景,并且分布式锁如果不作用于分布式系统就没有意义

    1.这里设置product为100,同时向服务器发送100个购买请求:
    可以发现,这里67被设置了两次,说明出现了冲突,因为没有设置锁
    test代码中设置了可重入锁,如果不设置锁需要将下面代码删除:

            RLock redissonLock = redissonClient.getLock("productKey");
            redissonLock.lock();
    
            redissonLock.unlock();
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述
    2.设置可重入锁RLock之后就不会出现问题:
    设置产品为105件,并在同一时间发送100个并发请求,最后理想是剩下5件产品:
    在这里插入图片描述

  • 相关阅读:
    RxJava/RxAndroid的基本使用方法(一)
    Flutter系列文章-Flutter UI进阶
    基于Python和mysql开发的智慧校园答题考试系统(源码+数据库+程序配置说明书+程序使用说明书)
    RabbitMQ 3.7.9版本中,Create Channel超时的常见原因及排查方法
    回Mixlab三天,“创造力团队”治好了我的精神内耗
    面试(03)————多线程
    bs4库爬取小说工具
    ios-关联对象
    JavaScript WebAPI、DOM知识整理
    个性化定义多个 Git 托管平台配置
  • 原文地址:https://blog.csdn.net/qq_38293932/article/details/126479967