最近在思考购物网站上的未领取订单到期主动勾销是怎么实现的,发现了一个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...