本文介绍: redis一个线程服务,那么所有的命令肯定会排队被redis执行redis提供的命令都是原子性的,百度搜索incrdecr就是说将对应key+1,key-1的值重新setredis中,而且很多都是认为incrdecr原子性的,那么现在就有一个问题,如果rediskey:a, value:100,那么100个线程并发执行decr操作,那么对应的keyvalue是不是应该为0?按照百度说法应该是。

一、前言

redis一个单线程的服务,那么所有的命令肯定会排队被redis执行redis提供的命令都是原子性的,百度搜索incrdecr就是说将对应的key+1,key-1的值重新setredis中,而且很多都是认为incrdecr原子性的,那么现在就有一个问题,如果rediskey:a, value:100,那么100个线程并发执行decr操作,那么对应的keyvalue是不是应该为0?

按照百度说法应该是。-1、-1、-1、-1进行排队等待redis执行,那么总有100的-1,那么value也是100,那么值肯定也是减去100了,最后的值是0?

这样的话,是不是incrdecr可以秒杀业务,不需要采用机制呢?

我们动手试试了下

package redisStockNumber;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * @author : fangcong
 * @date : 2023/3/22 15:22
 * @description : 类作用
 **/
public class RedisUtils {


    private static JedisPool jedisPool;

    static {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(20000);
        jedisPool = new JedisPool(jedisPoolConfig,"127.0.0.1", 6379);
        jedisPool.getResource().set("testNumber", ""+2024);
    }

    public static void main(String[] args) {
        int number = 2024;
        for(int i = 0; i < number ; i++){
            Thread thread
                    = new Thread(() -> {
                Jedis currentJedis = jedisPool.getResource();
                currentJedis.decrBy("testNumber", 1);
            });
            thread.start();
        }
		// sleep堵塞等到所有的子线程执行完成
		  try {
            Thread.sleep(60 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }	
        Jedis jedis = jedisPool.getResource();
        String testNumber = jedis.get("testNumber");
        System.out.println(testNumber);
    }

}

对应pom

     <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.6.0</version>
        </dependency>

引入一个jedis客户端来操作redis ,我们需要注意这里的jedis是一个非线程安全的类,因此可以使用jedispool对象来获得不同的线程客户端来模拟多个客户端。

我们得到的结果是0,这就说明incrdecr是我们上述说的那种原理,在多个客户端并发下是线程安全的。

二、为什么不能使用incrdecr来做下单操作呢?

比如我们库存量为1000?

那么如果并发数刚刚有1000个人来购买,那么并发执行1000次,这样库存量减去1000,就剩余0了。

但是如果有1200个人并发,那么就会并发执行1200次,那么库存量就为 -200了,那肯定就是超卖了,因此需要在decr之前进行判断库存量,如果库存大于0,则进行下单

Integer num = redis.getKey(a);
if(num > 0){
redis.decr(a,1);
}

但是这里有一个问题还是之前说的,如果有1200个人并发,那么同时拿到的num不是最新的,因此需要加锁保证这里num必须是最新的。

RLock lock =  redisson.tryLock(a);
lock.lock();
try{
	if(num > 0){
		redis.decr(a,1);
	}
 } finally {
        //解锁
        System.out.println("解锁..."+Thread.currentThread().getId());
        lock.unlock();
}

或者使用lua脚本,将业务逻辑封装lua脚本来保证其执行原子性。

原文地址:https://blog.csdn.net/qq_38240227/article/details/129712818

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_36802.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注