zoukankan      html  css  js  c++  java
  • 利用J.U.C.ScheduledThreadPoolExecutor来实现订单状态的实时变更

    来看一个场景:

    一个叫车应用里,用户下单叫车,行程单初始状态为“行程中”,当行程结束后,状态自动变更为“待支付”。

    叫车单有开始时间、结束时间。需求是要求当用户查看订单的时候,要及时体现出来最新的状态。就是说,如果是行程结束的订单,那么,展示的状态应该是“待支付”。 “行程中”状态的订单可以分享,“待支付”状态的订单可以发起支付。那么,程序怎么实现这个要求呢?

    用定时任务?

    不靠谱吧,间隔设置的再小也难免有延迟。况且,间隔设置太小,不停地操作数据库,会同时给应用服务器和数据库服务器带来压力。

    两种方案:

    【方案1】

    最直观的实现方式,这也往往是大家想不到的方式。每个涉及到订单表的select操作,都先执行改状态的操作。更新状态的sql很简单,类似于:

    update t_order set order_status= 'DaiZhiFu' where endTime≥now() and order_status='XingChengZhong'

    加切面类是不错的实现方式。

    只要用户操作或系统操作每次触发查询订单表,都执行这个update。显然,满足了需求。不过呢,弊端也显而易见,每次查单的时候并非都有需要变更状态的订单。如果查询频繁,因此而造成的系统负荷,可能得不偿失。

    【方案2】

    如题,利用juc下的ScheduledThreadPoolExecutor。ScheduledThreadPoolExecutor是java线程池的一员,jdk1.5之后提供的用来支持周期性任务的调度。ScheduledThreadPoolExecutor主要有两个成员,DelayedWorkQueue和ScheduledFutureTask。DelayedWorkQueue是一个延迟的阻塞队列(heap-based data structure,基于堆的数据结构),它会将入队的任务按照执行时间进行升序排序;ScheduledFutureTask,用来描述要执行的任务。通过调用delayedExecute方法来延时执行任务。 不说内部实现了,具体参考大神的blog:【JUC源码解析】ScheduledThreadPoolExecutor /  深入理解Java线程池:ScheduledThreadPoolExecutor。接下来直接看如何使用吧。

    ThreadPoolBean.java定义ScheduledThreadPoolExecutor线程池对象:

    package scheduledthreadpool;
    
    import com.google.common.util.concurrent.ThreadFactoryBuilder;
    import lombok.extern.slf4j.Slf4j;import java.util.concurrent.ScheduledThreadPoolExecutor;
    import java.util.concurrent.ThreadFactory;
    
    @Slf4j
    @Component
    public class ThreadPoolBean {
        @Bean
        public ScheduledThreadPoolExecutor bean() {
            ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
                    .setNameFormat("demo_pool_%d").build();
    
            ScheduledThreadPoolExecutor poolExecutor = new ScheduledThreadPoolExecutor(5, namedThreadFactory);
            return poolExecutor;
        }
    }

    OrderTask.java是修改订单状态的任务:

    package scheduledthreadpool;
    
    @Slf4j
    public class OrderTask implements Runnable {
        private String orderNo;
    
        public OrderTask(String orderNo) {
            log.info("{} insert", orderNo);
            this.orderNo = orderNo;
        }
    
        @Override
        public void run() {
            log.info("{} updated", orderNo);
        }
    }

    OrderController.java模拟用户下单叫车的api。

    package scheduledthreadpool;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.RestController;
    import java.util.concurrent.ScheduledThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    @Slf4j
    @RestController
    public class OrderController {
        @Autowired
        private ScheduledThreadPoolExecutor orderStatusUpdatePool;
    
        @ResponseBody
        @GetMapping("/order/add")
        public String add(@RequestParam("sec") int sec) {
            String orderNo = System.currentTimeMillis()+"_"+sec;
            orderStatusUpdatePool.schedule(new OrderTask(orderNo), sec, TimeUnit.SECONDS);
            return "ok:" + orderNo;
        }
    }

    MainApp.java是springboot启动程序。启动程序后,浏览器里访问http://localhost:8080/order/add?sec=**,多次改变sec参数的值,来模拟订单提交。从打印的log可以看出来,到了sec参数所指定的时间后,就会执行OrderTask的逻辑。

     【The End】

  • 相关阅读:
    旋转数组的最小数字
    二维数组中的查找问题--剑指offer面试题3
    百度软件开发实习生c++方向面经(一面)
    一些常考的智力题
    灵感闪现 篇 (一) 2d场景 3d 效果
    GameUnity 2.0 文档(四) 网格+四叉树 最优碰撞检测
    GameUnity 2.0 文档(三) 纸片人八方向
    GameUnity 2.0 文档(二) 纸片人系统
    GameUnity 2.0 文档(一) 事件机制
    GameUnity 2.0 发布倒计时
  • 原文地址:https://www.cnblogs.com/buguge/p/13603732.html
Copyright © 2011-2022 走看看