技术方案秒杀专题其他零散知识点

高并发下库存扣减解决方案--分布式锁

2019-02-21  本文已影响165人  小狼在IT

以下是个简单的库存扣减流程:


image.png

如果并发非常低的时候,基本就按这个流程走就行了。
而这个设计,并发量稍大时,就会导致超卖的情况出现,两个同时要9台手机的请求,同时查到库存有12台,那操作下来,就会导致超卖:


image.png

嗯,那么出于职业道德,得加把锁:


image.png

嗯,这个设计,在高并发但库存量极少的秒杀场景,或者库存很高但并发量不高的(每秒10个请求),都是可行解。
然而,这个相当于把程序串行化了。那么假设处理一个订单要200毫秒,在库存量很高(10万台),并发量极高(每秒1000个请求),有个请求就要等待200秒了,这个肯定不能接受的。

解决办法:
1.库存分段
将10万库存,分成100段,每段1000个库存。对应的,就有100把锁去锁这100个库存段了,可以满足100个线程同时跑。


image.png

这套方案确实可以解决高并发,高库存问题,然而库存分段也是个麻烦的事。
我这里还有个方案,虽然效率略低,但是跑起来应该还好。

2.库存占用


image.png

把串行化的步骤,改成了只是简单地往“库存占用表”插入数据即可,耗费的时间是低的,可以应付较高的并发量。

实现方式:

public static void main(String[] args) {

    try{
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6222");
        config.useSingleServer().setPassword("test");
        RedissonClient  finalRedisson = Redisson.create(config);
        //需求数量
        int requireQty = 9;
        for(int i=0;i<30;i++){
            Thread t = new Thread(()->{
                try{

                    RLock rLock = finalRedisson.getLock("myLock");
                    System.out.println(Thread.currentThread().getName()+ "开始");
                    RAtomicLong stockQty = finalRedisson.getAtomicLong("stockQty");
                    RAtomicLong stockOccupy = finalRedisson.getAtomicLong("stockOccupy");
                    rLock.lock();
                    long l1 = stockQty.get();
                    long l2 = stockOccupy.get();
                    long l = l1 - l2;
                    System.out.println(Thread.currentThread().getName() + "获得锁");
                    System.out.println(Thread.currentThread().getName() + "do something");
                    if(l >= requireQty) {
                        stockOccupy.set(stockOccupy.get()+requireQty);
                    }
                    rLock.unlock();
                    //创建订单,扣减库存
                    Thread.sleep(200);
                    if(l >= requireQty) {
                        System.out.println(Thread.currentThread().getName() + "done,库存剩下:" + l);
                    }
                    else {
                        System.out.println(Thread.currentThread().getName() + "库存不足,库存剩下:" + l);
                    }
                   // System.out.println(Thread.currentThread().getName() + "准备释放锁");
                    System.out.println(Thread.currentThread().getName() + "结束");
                }
                catch (Exception ex){
                    System.out.println(ex.getMessage());
                }

            });
            t.start();
        }
    }
    catch (Exception ex){
        System.out.println(ex.getMessage());
    }
    finally {

    }

}

执行前:


image.png
image.png

执行后:


image.png

部分执行结果:


image.png

剩下1个库存的时候,就跑步下去了。

上一篇下一篇

猜你喜欢

热点阅读