【并发】详解redis的incr、decr命令

【并发】详解redis的incr、decr命令redis 是一个单线程的服务 那么所有的命令肯定会排队被 redis 执行 redis 提供的命令都是原子性的 百度搜索 incr decr 就是说将对应的 key 1 key 1 的值重新 set 到 redis

大家好,欢迎来到IT知识分享网。

一、前言

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(); } // 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,这就说明了incr\decr是我们上述说的那种原理,在多个客户端并发下是线程安全的。

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

比如我们的库存量为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脚本来保证其执行原子性。

这里是先判断再去执行decr肯定有问题的啊,应该先执行decr再去判断就没问题了

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/137186.html

(0)
上一篇 2025-06-22 16:00
下一篇 2025-06-22 16:10

相关推荐

发表回复

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

关注微信