多线程案例落地 - 库存扣减请求合并、库存一致性保证

文章内容已经收录在《高级技术专家成长笔记》,欢迎订阅专栏!
从原理、系统设计出发,直击面试难点,实现更高维度的降维打击!

多线程案例落地 - 库存扣减请求合并、库存一致性保证

海哥也给出了合并库存扣减请求的 Demo,是一个多线程的 Demo,对提升并发掌握很有帮助,这里也整理一篇文章进行分析!

参考 B 站 up 主《极海Channel》,视频链接:https://www.bilibili.com/video/BV1Hv4y1P7ta

背景

对于库存扣减流程中的优化,最主要的优化就是库存扣减请求的合并,海哥也给出了 Demo,这里将整体设计、演进思路整理出来

库存扣减请求整体合并思路:针对热门商品进行合并,因此需要判断商品并发数,如果超过阈值,则判定为比较热门的商品,进行库存扣减请求的合并,此时会将库存扣减请求提交到队列,并且将用户线程阻塞,等待异步线程处理,处理完成之后,通知用户线程响应结果即可

这里会对海哥给出的代码进行分析,并且整理评论区中给出的问题

库存扣减请求的合并,主要流程为:

  • 用户提交库存扣减请求
  • 将用户请求的库存扣减请求入队,用户线程阻塞等待 200ms,等待异步线程处理请求
  • 异步线程从队列中取出用户扣减请求,进行合并,再执行库存的扣减
  • 异步线程处理完之后,唤醒用户线程,并响应结果

接下来将各个步骤拆解开,来分析库存扣减合并的 Demo

1、库存扣减操作

先看库存扣减操作的实现,主要是用户请求进来之后,需要将用户请求加入到队列中,等待异步线程处理,此时用户线程阻塞等待处理,阻塞时间为 200ms

这里就涉及到了阻塞,采用了 wait() 来实现阻塞

image-20241127111702476

对应代码如下,对于阈值判断、队列的创建,不是核心逻辑,先略过,这里主要关注用户请求的入队操作,以及阻塞等待操作如何实现:

// 定义阻塞队列,存放用户请求
private BlockingQueue<RequestPromise> queue = new LinkedBlockingQueue<>(10);

public Result operate(UserRequest userRequest) throws InterruptedException {
    // TODO 阈值判断
    // TODO 队列的创建
    
    // 1、创建 RequestPromise 封装用户请求,通过该对象,实现用户线程的阻塞和唤醒
    RequestPromise requestPromise = new RequestPromise(userRequest);

    synchronized (requestPromise) {
        // 2、用户请求入队
        boolean enqueueSuccess = queue.offer(requestPromise, 100, TimeUnit.MILLISECONDS);
        if (! enqueueSuccess) {
            return new Result(false, "系统繁忙");
        }
        try {
            // 3、用户请求阻塞 200ms,等待请求被处理
            requestPromise.wait(200);
            // 4、根据 Result 判断是否为用户等待 200ms 超时
            if (requestPromise.getResult() == null) {
                return new Result(false, "等待超时");
            }
        } catch (InterruptedException e) {
            return new Result(false, "被中断");
        }
    }
    return requestPromise.getResult();
}

核心有两个操作:

  • queue.offer() :将用户请求入队,之后异步线程会从队列取出请求,进行 合并处理
  • requestPromise.wait(200) :将用户线程阻塞 200ms,等待处理,如果 200ms 之内,异步线程仍然没有处理完毕,会判断 requestPromise.getResult() == null ,就算 等待超时 ,此时,直接返回结果为扣减失败即可

这里需要将入队操作放在 synchronized 同步代码块内(后边会详细解释):

这里假如将 queue.offer() 放在 synchronized 外部,那么假如用户请求刚加入队列之后,该请求就立即被异步线程处理,异步线程处理之后会通过 notify() 去唤醒这个用户线程,此时用户线程还没有执行 wait() 操作,也就是 no

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

11来了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值