大家好,欢迎来到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