最近在思考购物网站上的未领取订单到期主动勾销是怎么实现的,发现了一个DelayQueue队列能够实现,所以来整顿一下。。。

DelayQueue

java提早队列提供了在指定工夫能力获取队列元素的性能,队列头元素是最靠近过期的元素。没有过期元素的话,应用poll()办法会返回null值,超时断定是通过getDelay(TimeUnit.NANOSECONDS)办法的返回值小于等于0来判断。

1. 新建Spring Boot我的项目

1.1 pom.xml

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter</artifactId></dependency><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-web</artifactId></dependency><dependency>    <groupId>cn.hutool</groupId>    <artifactId>hutool-all</artifactId>    <version>5.4.2</version></dependency>

1.2 application.yml

server:  port: 8888order:  isStarted: 1 # 是否开启主动勾销性能(0敞开,1开启)

1.3 新建Order订单类

/** * 订单类 * @author zhouzhaodong */public class Order implements Delayed {    /**     * 订单号     */    private String orderNo;    /**     * 用户id     */    private String userId;    /**     * 订单状态(0待领取,1已领取,2已勾销)     */    private Integer status;    /**     * 订单创立工夫     */    private Date createTime;    /**     * 订单勾销工夫     */    private Date cancelTime;    public String getOrderNo() {        return orderNo;    }    public void setOrderNo(String orderNo) {        this.orderNo = orderNo;    }    public String getUserId() {        return userId;    }    public void setUserId(String userId) {        this.userId = userId;    }    public Integer getStatus() {        return status;    }    public void setStatus(Integer 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;    }    public Order(String orderNo, String userId, Integer status, Date createTime, Date cancelTime) {        this.orderNo = orderNo;        this.userId = userId;        this.status = status;        this.createTime = createTime;        this.cancelTime = cancelTime;    }    @Override    public String toString() {        return "Order{" +                "orderNo='" + orderNo + '\'' +                ", userId='" + userId + '\'' +                ", status=" + status +                ", createTime=" + createTime +                ", cancelTime=" + cancelTime +                '}';    }    /**     * 取得延迟时间,用过期工夫-以后工夫,工夫单位须要对立     * @param unit     * @return     */    @Override    public long getDelay(TimeUnit unit) {        //上面用到unit.convert()办法,其实在这个小场景不须要用到,只是学习一下如何应用罢了        return unit.convert(cancelTime.getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS);    }    /**     * 用于提早队列外部比拟排序,以后工夫的延迟时间 - 比拟对象的延迟时间     * @param o     * @return     */    @Override    public int compareTo(Delayed o) {        //这里依据勾销工夫来比拟,如果勾销工夫小的,就会优先被队列提取进去        return this.getCancelTime().compareTo(((Order) o).getCancelTime());    }}

1.4 新建CancelOrderService

/** * 勾销订单service类 * @author zhouzhaodong */public interface CancelOrderService {    /**     * 勾销订单     */    void cancelOrder();    /**     * 获取队列     * @return     */    DelayQueue<Order> getOrder();}

1.5 新建servie实现类

/** * 勾销订单实现类 * * @author zhouzhaodong */@Servicepublic class CancelOrderServiceImpl implements CancelOrderService {    /**     * 是否开启主动勾销性能     */    @Value("${order.isStarted}")    private int isStarted;    /**     * 提早队列,用来寄存订单对象     */    DelayQueue<Order> queue = new DelayQueue<>();    @Resource    private ThreadPoolTaskExecutor executorService;    @Override    public void cancelOrder() {        //新建一个线程,用来模仿定时勾销订单job        executorService.submit(()->{            try {                System.out.println("开启主动勾销订单job,以后工夫:" + DateUtil.date());                while (isStarted == 1) {                    try {                        Order order = queue.take();                        order.setStatus(2);                        System.out.println("订单:" + order.getOrderNo() + "付款超时,主动勾销,以后工夫:" + DateUtil.date());                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            } catch (Exception e) {                e.printStackTrace();            }        });    }    @Override    public DelayQueue<Order> getOrder(){        executorService.submit(()->{            try {                Date date = DateUtil.date();                queue.add(new Order("SO001", "001", 0, date, DateUtil.offset(date, DateField.SECOND, 3)));                queue.add(new Order("SO002", "002", 0, DateUtil.offset(date, DateField.SECOND, 3), DateUtil.offset(date, DateField.SECOND, 6)));                queue.add(new Order("SO003", "003", 0, DateUtil.offset(date, DateField.SECOND, 6), DateUtil.offset(date, DateField.SECOND, 9)));                queue.add(new Order("SO004", "004", 0, DateUtil.offset(date, DateField.SECOND, 9), DateUtil.offset(date, DateField.SECOND, 12)));                queue.add(new Order("SO005", "005", 0, DateUtil.offset(date, DateField.SECOND, 12), DateUtil.offset(date, DateField.SECOND, 15)));                queue.add(new Order("SO006", "006", 0, DateUtil.offset(date, DateField.SECOND, 15), DateUtil.offset(date, DateField.SECOND, 18)));            } catch (Exception e) {                e.printStackTrace();            }        });        return queue;    }}

1.6 新建controller

/** * 控制器 * @author zhouzhaodong */@RestControllerpublic class CancelOrderController {    @Resource    CancelOrderService cancelOrderService;    @RequestMapping("/")    public void cancelOrder(){        cancelOrderService.getOrder();        cancelOrderService.cancelOrder();    }    @RequestMapping("/queue")    public void getOrder(){        cancelOrderService.getOrder();    }    }

2. 测试

2.1 启动我的项目,拜访localhost:8888/

2.2 拜访localhost:8888/queue

因为队列中曾经没有订单了,所以控制台不再打印相干订单勾销的信息,所以咱们再创立一遍方才的订单,察看控制台打印信息:

至此,咱们简略的订单定时勾销性能就实现了,当然能够依据本人具体的要求进行批改!

集体博客地址:

http://www.zhouzhaodong.xyz

GitHub源码地址:

https://github.com/zhouzhaodo...