Redis的分布式锁实现代码(商品秒杀)

准备工作

下载Apache JMeter软件:模拟多线程,高并发情况

导入依赖

导入redis包
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
 </dependency>

分布式锁代码

该方法有三个接口
①init():初始化商品数量为100
②synchronizedBuy():使用synchronizedBuy锁模拟商品秒杀
③redisBuy():使用redis分布式锁模拟商品秒杀
@RestController
public class OrderController {

    @Autowired
    private RedisTemplate redisTemplate;

    @GetMapping("/initCount")
    public String init(){
        redisTemplate.opsForValue().set("count","100");
        return "库存初始化成功";
    }


    /**
     * @author:
     * @description: synchronized锁
     * @date: 2021/10/23
     * @param
     * @return java.lang.String
     */
    @GetMapping("/synchronizedBuy")
    public String synchronizedBuy(){
        synchronized (OrderController.class){
            Integer count = Integer.parseInt(redisTemplate.opsForValue().get("count").toString());
            if (count > 0)
            {
                Integer realCount = count - 1;
                System.out.println("购买商品成功,库存为:" + realCount.toString());
                redisTemplate.opsForValue().set("count",realCount.toString());
            }else {
                System.out.println("库存不足,购买失败");
            }
            return "ok";
        }
    }


    /**
     * @author:
     * @description: 使用分布式锁
     * @date: 2021/10/23
     * @param
     * @return java.lang.String
     */
    @GetMapping("/redisBuy")
    public String redisBuy(){
        String lockKey = "ShangPin";
        String clientId = UUID.randomUUID().toString();
        try {
            //setnx加锁
            //setIfAbsent()方法:如果这个锁已经存在,则返回flase,获得锁失败,如果返回true则说明加锁成功
            Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey,clientId,10, TimeUnit.SECONDS);
            if (lock)
            {
                //执行购买业务
                int count1 = Integer.parseInt(redisTemplate.opsForValue().get("count").toString());
                if (count1 > 0)
                {
                    Integer realCount = count1 - 1;
                    System.out.println("购买商品成功,库存为:" + realCount.toString());
                    redisTemplate.opsForValue().set("count",realCount.toString());
                }else {
                    System.out.println("库存不足,购买失败");
                }
            }else {
                try {
                     //获取锁失败,每隔0.1秒再获取
                     Thread.sleep(100);
                     redisBuy();
                }catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //删锁,判断当前客户端的clientId与redis持有的一样
            if(clientId.equals(redisTemplate.opsForValue().get(lockKey)))
            redisTemplate.delete(lockKey);
        }
        return "ok";
    }
}

启动项目

为了模拟集群环境,idea需要启动两个端口不一样的服务,方法如下:

模拟redis高并发的场景 redis秒杀高并发代码_redis


模拟redis高并发的场景 redis秒杀高并发代码_集群环境_02


修改好后,端口为17055时启动项目

模拟redis高并发的场景 redis秒杀高并发代码_模拟redis高并发的场景_03


再把端口修改为17054,再次启动项目

模拟redis高并发的场景 redis秒杀高并发代码_分布式锁_04

启动Jmeter

使用Apache Jmeter软件模拟多线程并发。

Jmeter分别调用17055端口和17054端口的synchronizedBuy()接口和redisBuy()接口,分别模拟80个线程,以及17055端口的init()接口,具体配置如下。

模拟redis高并发的场景 redis秒杀高并发代码_java_05


模拟redis高并发的场景 redis秒杀高并发代码_java_06

调用17054的synchronizedBuy()接口

模拟redis高并发的场景 redis秒杀高并发代码_redis_07


模拟redis高并发的场景 redis秒杀高并发代码_分布式锁_08


调用17055的synchronizedBuy()接口

模拟redis高并发的场景 redis秒杀高并发代码_分布式锁_09


其余几个接口可仿照上面内容进行创建。

运行结果

首先调用init()接口进行商品初始化操作。

单击环境下,使用synchronized锁

只调用一个接口,结果如下所示:

模拟redis高并发的场景 redis秒杀高并发代码_redis_10


商品有100件,只模拟了80个线程,所有商品应该卖出80件,可以看出在单击环境下是哟synchronized锁没有问题。

购买商品成功,库存为:99
购买商品成功,库存为:98
购买商品成功,库存为:97
购买商品成功,库存为:96
购买商品成功,库存为:95
购买商品成功,库存为:94
购买商品成功,库存为:93
购买商品成功,库存为:92
购买商品成功,库存为:91
购买商品成功,库存为:90
购买商品成功,库存为:89
购买商品成功,库存为:88
购买商品成功,库存为:87
购买商品成功,库存为:86
购买商品成功,库存为:85
购买商品成功,库存为:84
购买商品成功,库存为:83
购买商品成功,库存为:82
购买商品成功,库存为:81
购买商品成功,库存为:80
购买商品成功,库存为:79
购买商品成功,库存为:78
购买商品成功,库存为:77
购买商品成功,库存为:76
购买商品成功,库存为:75
购买商品成功,库存为:74
购买商品成功,库存为:73
购买商品成功,库存为:72
购买商品成功,库存为:71
购买商品成功,库存为:70
购买商品成功,库存为:69
购买商品成功,库存为:68
购买商品成功,库存为:67
购买商品成功,库存为:66
购买商品成功,库存为:65
购买商品成功,库存为:64
购买商品成功,库存为:63
购买商品成功,库存为:62
购买商品成功,库存为:61
购买商品成功,库存为:60
购买商品成功,库存为:59
购买商品成功,库存为:58
购买商品成功,库存为:57
购买商品成功,库存为:56
购买商品成功,库存为:55
购买商品成功,库存为:54
购买商品成功,库存为:53
购买商品成功,库存为:52
购买商品成功,库存为:51
购买商品成功,库存为:50
购买商品成功,库存为:49
购买商品成功,库存为:48
购买商品成功,库存为:47
购买商品成功,库存为:46
购买商品成功,库存为:45
购买商品成功,库存为:44
购买商品成功,库存为:43
购买商品成功,库存为:42
购买商品成功,库存为:41
购买商品成功,库存为:40
购买商品成功,库存为:39
购买商品成功,库存为:38
购买商品成功,库存为:37
购买商品成功,库存为:36
购买商品成功,库存为:35
购买商品成功,库存为:34
购买商品成功,库存为:33
购买商品成功,库存为:32
购买商品成功,库存为:31
购买商品成功,库存为:30
购买商品成功,库存为:29
购买商品成功,库存为:28
购买商品成功,库存为:27
购买商品成功,库存为:26
购买商品成功,库存为:25
购买商品成功,库存为:24
购买商品成功,库存为:23
购买商品成功,库存为:22
购买商品成功,库存为:21
购买商品成功,库存为:20
集群环境下,使用synchronized锁

同时选中调用两个不同端口的synchronizedBuy()接口( 模拟集群环境下使用synchronized锁实现商品秒杀的现象)

模拟redis高并发的场景 redis秒杀高并发代码_模拟redis高并发的场景_11


结果如下:

模拟redis高并发的场景 redis秒杀高并发代码_分布式锁_12


模拟redis高并发的场景 redis秒杀高并发代码_java_13

购买商品成功,库存为:95
购买商品成功,库存为:94
购买商品成功,库存为:93
购买商品成功,库存为:92
购买商品成功,库存为:91
购买商品成功,库存为:90
购买商品成功,库存为:89
购买商品成功,库存为:88
购买商品成功,库存为:87
购买商品成功,库存为:86
购买商品成功,库存为:85
购买商品成功,库存为:84
购买商品成功,库存为:83
购买商品成功,库存为:82
购买商品成功,库存为:81
购买商品成功,库存为:80
购买商品成功,库存为:78
购买商品成功,库存为:77
购买商品成功,库存为:76
购买商品成功,库存为:75
购买商品成功,库存为:74
购买商品成功,库存为:73
购买商品成功,库存为:72
购买商品成功,库存为:71
购买商品成功,库存为:70
购买商品成功,库存为:69
购买商品成功,库存为:67
购买商品成功,库存为:65
购买商品成功,库存为:64
购买商品成功,库存为:62
购买商品成功,库存为:61
购买商品成功,库存为:60
购买商品成功,库存为:58
购买商品成功,库存为:57
购买商品成功,库存为:56
购买商品成功,库存为:55
购买商品成功,库存为:54
购买商品成功,库存为:53
购买商品成功,库存为:51
购买商品成功,库存为:50
购买商品成功,库存为:49
购买商品成功,库存为:48
购买商品成功,库存为:47
购买商品成功,库存为:46
购买商品成功,库存为:45
购买商品成功,库存为:43
购买商品成功,库存为:42
购买商品成功,库存为:40
购买商品成功,库存为:39
购买商品成功,库存为:38
购买商品成功,库存为:37
购买商品成功,库存为:36
购买商品成功,库存为:35
购买商品成功,库存为:34
购买商品成功,库存为:33
购买商品成功,库存为:32
购买商品成功,库存为:30
购买商品成功,库存为:28
购买商品成功,库存为:27
购买商品成功,库存为:25
购买商品成功,库存为:24
购买商品成功,库存为:23
购买商品成功,库存为:22
购买商品成功,库存为:21
购买商品成功,库存为:19
购买商品成功,库存为:18
购买商品成功,库存为:17
购买商品成功,库存为:15
购买商品成功,库存为:13
购买商品成功,库存为:12
购买商品成功,库存为:11
购买商品成功,库存为:10
购买商品成功,库存为:9
购买商品成功,库存为:8
购买商品成功,库存为:7
购买商品成功,库存为:6
购买商品成功,库存为:5
购买商品成功,库存为:4
购买商品成功,库存为:3
购买商品成功,库存为:2
购买商品成功,库存为:99
购买商品成功,库存为:98
购买商品成功,库存为:97
购买商品成功,库存为:96
购买商品成功,库存为:95
购买商品成功,库存为:94
购买商品成功,库存为:93
购买商品成功,库存为:92
购买商品成功,库存为:92
购买商品成功,库存为:91
购买商品成功,库存为:90
购买商品成功,库存为:89
购买商品成功,库存为:88
购买商品成功,库存为:87
购买商品成功,库存为:86
购买商品成功,库存为:85
购买商品成功,库存为:84
购买商品成功,库存为:83
购买商品成功,库存为:82
购买商品成功,库存为:80
购买商品成功,库存为:79
购买商品成功,库存为:78
购买商品成功,库存为:77
购买商品成功,库存为:76
购买商品成功,库存为:71
购买商品成功,库存为:70
购买商品成功,库存为:69
购买商品成功,库存为:68
购买商品成功,库存为:66
购买商品成功,库存为:65
购买商品成功,库存为:64
购买商品成功,库存为:63
购买商品成功,库存为:62
购买商品成功,库存为:61
购买商品成功,库存为:60
购买商品成功,库存为:59
购买商品成功,库存为:57
购买商品成功,库存为:56
购买商品成功,库存为:55
购买商品成功,库存为:54
购买商品成功,库存为:53
购买商品成功,库存为:52
购买商品成功,库存为:51
购买商品成功,库存为:50
购买商品成功,库存为:49
购买商品成功,库存为:48
购买商品成功,库存为:47
购买商品成功,库存为:46
购买商品成功,库存为:45
购买商品成功,库存为:44
购买商品成功,库存为:43
购买商品成功,库存为:42
购买商品成功,库存为:41
购买商品成功,库存为:40
购买商品成功,库存为:39
购买商品成功,库存为:38
购买商品成功,库存为:37
购买商品成功,库存为:36
购买商品成功,库存为:35
购买商品成功,库存为:34
购买商品成功,库存为:32
购买商品成功,库存为:31
购买商品成功,库存为:30
购买商品成功,库存为:29
购买商品成功,库存为:28
购买商品成功,库存为:27
购买商品成功,库存为:26
购买商品成功,库存为:25
购买商品成功,库存为:24
购买商品成功,库存为:23
购买商品成功,库存为:22
购买商品成功,库存为:21
购买商品成功,库存为:20
购买商品成功,库存为:19
购买商品成功,库存为:17
购买商品成功,库存为:16
购买商品成功,库存为:15
购买商品成功,库存为:14
购买商品成功,库存为:13
购买商品成功,库存为:12

可以看出商品已经超卖了。

集群环境下,使用redis分布式锁

模拟redis高并发的场景 redis秒杀高并发代码_集群环境_14


运行结果:

模拟redis高并发的场景 redis秒杀高并发代码_redis_15


模拟redis高并发的场景 redis秒杀高并发代码_分布式锁_16

购买商品成功,库存为:94
购买商品成功,库存为:93
购买商品成功,库存为:88
购买商品成功,库存为:87
购买商品成功,库存为:85
购买商品成功,库存为:83
购买商品成功,库存为:82
购买商品成功,库存为:81
购买商品成功,库存为:79
购买商品成功,库存为:73
购买商品成功,库存为:67
购买商品成功,库存为:62
购买商品成功,库存为:61
购买商品成功,库存为:58
购买商品成功,库存为:57
购买商品成功,库存为:56
购买商品成功,库存为:55
购买商品成功,库存为:50
购买商品成功,库存为:49
购买商品成功,库存为:47
购买商品成功,库存为:46
购买商品成功,库存为:45
购买商品成功,库存为:44
购买商品成功,库存为:43
购买商品成功,库存为:41
购买商品成功,库存为:40
购买商品成功,库存为:39
购买商品成功,库存为:38
购买商品成功,库存为:37
购买商品成功,库存为:34
购买商品成功,库存为:33
购买商品成功,库存为:32
购买商品成功,库存为:28
购买商品成功,库存为:27
购买商品成功,库存为:23
购买商品成功,库存为:22
购买商品成功,库存为:18
购买商品成功,库存为:17
购买商品成功,库存为:15
购买商品成功,库存为:14
购买商品成功,库存为:13
购买商品成功,库存为:12
购买商品成功,库存为:9
购买商品成功,库存为:8
购买商品成功,库存为:7
购买商品成功,库存为:4
购买商品成功,库存为:3
购买商品成功,库存为:2
库存不足,购买失败
库存不足,购买失败
库存不足,购买失败
购买商品成功,库存为:86
购买商品成功,库存为:84
购买商品成功,库存为:80
购买商品成功,库存为:78
购买商品成功,库存为:77
购买商品成功,库存为:76
购买商品成功,库存为:75
购买商品成功,库存为:74
购买商品成功,库存为:72
购买商品成功,库存为:71
购买商品成功,库存为:70
购买商品成功,库存为:69
购买商品成功,库存为:68
购买商品成功,库存为:66
购买商品成功,库存为:65
购买商品成功,库存为:64
购买商品成功,库存为:63
购买商品成功,库存为:60
购买商品成功,库存为:59
购买商品成功,库存为:54
购买商品成功,库存为:53
购买商品成功,库存为:52
购买商品成功,库存为:51
购买商品成功,库存为:48
购买商品成功,库存为:42
购买商品成功,库存为:36
购买商品成功,库存为:35
购买商品成功,库存为:31
购买商品成功,库存为:30
购买商品成功,库存为:29
购买商品成功,库存为:26
购买商品成功,库存为:25
购买商品成功,库存为:24
购买商品成功,库存为:21
购买商品成功,库存为:20
购买商品成功,库存为:19
购买商品成功,库存为:16
购买商品成功,库存为:11
购买商品成功,库存为:10
购买商品成功,库存为:6
购买商品成功,库存为:5
购买商品成功,库存为:1
购买商品成功,库存为:0
库存不足,购买失败
库存不足,购买失败

可以看出集群环境下使用redis分布式锁刚好买了100件商品,不会出现超卖现象。