redis是一个单线程的服务,那么所有的命令肯定会排队被redis执行,redis提供的命令都是原子性的,百度搜索incr\decr就是说将对应的key+1,key-1的值重新set到redis中,而且很多都是认为incr\decr原子性的,那么现在就有一个问题,如果redis的key:a, value:100,那么100个线程并发执行decr操作,那么对应的key的value是不是应该为0?
按照百度的说法,应该是。-1、-1、-1、-1进行排队等待redis执行,那么总有100的-1,那么value也是100,那么值肯定也是减去100了,最后的值是0?
这样的话,是不是incr\decr可以做秒杀业务,不需要采用锁机制呢?
我们动手试试了下
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();}Jedis jedis = jedisPool.getResource();String testNumber = jedis.get("testNumber");System.out.println(testNumber);}}
对应pom
redis.clients jedis 3.6.0
引入一个jedis客户端来操作redis ,我们需要注意这里的jedis是一个非线程安全的类,因此可以使用jedispool对象来获得不同的线程客户端来模拟多个客户端。
我们得到的结果是411,这就说明了incr\decr并不是我们上述说的那种原理,在多个客户端并发下是线程不安全的。
但是从官方介绍上其实也不太清楚该内存含义,如果按照官方介绍,我还是以为incr是 +1 、 +1 、+1进行执行。
因为写了一个测试文件,验证了incr并不是+1、+1这样的实现的,因此猜测
在使用 DECRBY 命令减少库存时,每个命令执行时会读取当前键的值,然后对这个值进行减少操作,最后将减少后的结果保存回 Redis 中。如果有多个客户端同时执行 DECRBY 命令,那么 Redis 会按照客户端发送命令的顺序执行这些命令,并且在执行命令时会保证读取到的值是最新的,从而确保每个客户端都在最新的库存量上进行减少操作。
也就是incr会。 读值+1 、 读值+1 ,然后redis会将读值+1这个结果重新执行一个类型set命令将对应的key的value覆盖成最新的。
因此在多线程下 可以存在多个客户端读的值会相同,而不是读的是最新的值。
如果有人明确incr \decr底层是怎么样的一个实现逻辑请留言,麻烦谢谢了
上一篇: 燮理阴阳的成语接龙