使用DelayQueue模拟订单自动取消功能

使用DelayQueue模拟订单自动取消功能

背景:

今天要做一个作业:模拟一个使用DelayQueue的场景。于是我就做一个模拟订单自动取消的功能吧。需求以及实现思路如下:
需求:
1. 生成6个订单,从1号到6号订单,它们的创建时间依次递增3秒。
2. 规定如果一个订单在3秒内状态还是“CREATED”状态,那么就改成“CANCELED”状态。
实现思路:
1. 定义订单类,其实现Delayed接口,为啥要实现这个接口呢?是因为存放到DelayQueue里的元素都要实现Delayed接口,用于判断是否到了超时时间。
2. 在main方法里启动两个线程,第一个线程用来往DelayQueue里添加6个订单,这6个订单的创建时间依次递增3秒。另一个线程是循环从DelayQueue里面获取超时的订单,改成取消状态,然后打印出日志出来。超时的条件是该订单的超时时间字段大于或等于当前系统时间。

代码实现:

先定义一个订单类,实现了Delayed接口:

package top.usjava.learn.springbootlearn.vo;

import java.util.Date;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

/**
 * 订单类,用于存放订单头信息
 *
 * @author Owen
 * @date 2018/9/3 14:10
 */
public class Order implements Delayed {
    String orderNo;
    String receiveName;
    int cost;
    String status;
    Date createTime;
    Date cancelTime;

    public Order(String orderNo, String receiveName, int cost, String status, Date createTime, Date cancelTime) {
        this.orderNo = orderNo;
        this.receiveName = receiveName;
        this.cost = cost;
        this.status = status;
        this.createTime = createTime;
        this.cancelTime = cancelTime;
    }

    public String getOrderNo() {
        return orderNo;
    }

    public void setOrderNo(String orderNo) {
        this.orderNo = orderNo;
    }

    public String getReceiveName() {
        return receiveName;
    }

    public void setReceiveName(String receiveName) {
        this.receiveName = receiveName;
    }

    public int getCost() {
        return cost;
    }

    public void setCost(int cost) {
        this.cost = cost;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Date getCancelTime() {
        return cancelTime;
    }

    public void setCancelTime(Date cancelTime) {
        this.cancelTime = cancelTime;
    }

    @Override
    public long getDelay(TimeUnit unit) {
        //下面用到unit.convert()方法,其实在这个小场景不需要用到,只是学习一下如何使用罢了
        long l = unit.convert(cancelTime.getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
        return l;
    }

    @Override
    public int compareTo(Delayed o) {
        //这里根据取消时间来比较,如果取消时间小的,就会优先被队列提取出来
        return this.getCancelTime().compareTo(((Order) o).getCancelTime());
    }
}

测试类,先往DelayQueue插入6个订单,然后等待这些订单超时时间到了后,就取出来改状态:

package top.usjava.learn.springbootlearn.testmain;

import top.usjava.learn.springbootlearn.vo.Order;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.concurrent.DelayQueue;

/**
 * 第一周作业:模拟一个使用DelayQueue的场景
 * 这里模拟的是订单下达之后,如果一直都还没支付,也就是停留在创建状态的话,就将其改成取消状态。
 *
 * @author Owen
 * @date 2018/8/27 21:20
 */
public class TestDelayQueue {
    //是否开启自动取消功能
    int isStarted = 1;
    //延迟队列,用来存放订单对象
    DelayQueue queue = new DelayQueue();

    public static void main(String[] args) {
        TestDelayQueue testDelayQueue = new TestDelayQueue();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        //新建一个线程,用来模拟定时取消订单job
        Thread t1 = new Thread(() -> {
            System.out.println("开启自动取消订单job,当前时间:"+ LocalDateTime.now().format(formatter));
            while (testDelayQueue.isStarted == 1) {
                try {
                    Order order = testDelayQueue.queue.take();
                    order.setStatus("CANCELED");

                    System.out.println("订单:" + order.getOrderNo() + "付款超时,自动取消,当前时间:"+ LocalDateTime.now().format(formatter));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();

        //新建一个线程,模拟提交订单
        Thread t2 = new Thread(() -> {
            //定义最早的订单的创建时间
            long beginTime = System.currentTimeMillis();
            //下面模拟6个订单,每个订单的创建时间依次延后3秒
            testDelayQueue.queue.add(new Order("SO001", "A", 100, "CREATED", new Date(beginTime), new Date(beginTime + 3000)));
            beginTime += 3000L;
            testDelayQueue.queue.add(new Order("SO002", "B", 100, "CREATED", new Date(beginTime), new Date(beginTime + 3000)));
            beginTime += 3000L;
            testDelayQueue.queue.add(new Order("SO003", "C", 100, "CREATED", new Date(beginTime), new Date(beginTime + 3000)));
            beginTime += 3000L;
            testDelayQueue.queue.add(new Order("SO004", "D", 100, "CREATED", new Date(beginTime), new Date(beginTime + 3000)));
            beginTime += 3000L;
            testDelayQueue.queue.add(new Order("SO005", "E", 100, "CREATED", new Date(beginTime), new Date(beginTime + 3000)));
            beginTime += 3000L;
            testDelayQueue.queue.add(new Order("SO006", "F", 100, "CREATED", new Date(beginTime), new Date(beginTime + 3000)));
        });
        t2.start();
    }

}

运行结果:
使用DelayQueue模拟订单自动取消功能_第1张图片

上面的测试类的两个线程几乎是同一时间运行的,因此第一个订单可以认为是2018-09-04 14:19:57这个时间点创建的。然后从打印结果来看,基本上每个订单一旦到了超时时间,就被队列提出出来,进行取消操作了。这样,就完成了这个小小的模拟自动取消订单需求。

题外话:TimeUnit的使用

直接看代码和效果就知道怎么用了:
例子1:

public static void main(String[] args) {
        TimeUnit timeUnit = TimeUnit.MINUTES;
        long convert = timeUnit.convert(61, TimeUnit.SECONDS);
        System.out.println(convert);

    }

运行结果:
使用DelayQueue模拟订单自动取消功能_第2张图片
例子2:

public static void main(String[] args) {
        TimeUnit timeUnit = TimeUnit.MINUTES;
        long convert = timeUnit.convert(59, TimeUnit.SECONDS);
        System.out.println(convert);

    }

运行结果:
使用DelayQueue模拟订单自动取消功能_第3张图片

由此看出,上面例子就是把第一个参数看做是秒数,然后转成相应的分数返回,满60秒就返回1分钟,不满就返回0分钟。其他时间单位转换是同样的用法和效果,例如3601秒就是满1小时,3501秒就是0小时。

你可能感兴趣的:(java练习)