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】

  • 相关阅读:
    HDU 6143 Killer Names【dp递推】【好题】【思维题】【阅读题】
    HDU 6143 Killer Names【dp递推】【好题】【思维题】【阅读题】
    POJ 3974 Palindrome【manacher】【模板题】【模板】
    POJ 3974 Palindrome【manacher】【模板题】【模板】
    HDU 6127 Hard challenge【计算机几何】【思维题】
    HDU 6127 Hard challenge【计算机几何】【思维题】
    HDU 6129 Just do it【杨辉三角】【思维题】【好题】
    HDU 6129 Just do it【杨辉三角】【思维题】【好题】
    HDU 3037 Saving Beans【Lucas定理】【模板题】【模板】【组合数取余】
    8.Math 对象
  • 原文地址:https://www.cnblogs.com/buguge/p/13603732.html
Copyright © 2011-2022 走看看