延时队列DelayQueue 订单过期自动清除
模拟一个场景,用户下单后迟迟未付款, 我们需要在30分钟后取消订单, 释放库存.
首先做个延迟队列的泛型类 需要实现Delayed
@Data public class DelayTask implements Delayed { private String taskName;//任务名称 private long expire ;//到期时间 public DelayTask(String taskName, long secondsDelay) { super(); this.taskName = taskName; long now = System.currentTimeMillis(); this.expire = now+ (secondsDelay*1000); } //用于队列中排序过期时间 @Override public int compareTo(Delayed o) { return (int) (this.getDelay(TimeUnit.MILLISECONDS) -o.getDelay(TimeUnit.MILLISECONDS)); } //用于获取过期时间 @Override public long getDelay(TimeUnit unit) { return unit.convert(this.expire - System.currentTimeMillis() , TimeUnit.MILLISECONDS); } }
做一个服务类,对队列做一层封装, 主要用于填充和手动剔除
@Service @Slf4j @Getter public class DelayService { private final DelayQueue<DelayTask> delayQueue = new DelayQueue<>(); public void put(DelayTask task) { delayQueue.put(task); } public boolean remove(DelayTask task) { return delayQueue.remove(task); } public boolean remove(String taskName) { DelayTask[] array = delayQueue.toArray(new DelayTask[]{}); if (array.length > 0) { for (DelayTask task : array) { if (task.getTaskName().equals(taskName)) { return remove(task); } } } return true; } }
最后是一个管理类,用一个线程来监听 当延迟队列中获取到过期数据时,进行相关操作
@Component @Slf4j public class DelayManage { @Resource private DelayService delayService; /** * 服务器启动时,自动加载待支付订单 */ @PostConstruct public void initOrderStatus() { System.out.println("来了啊initOrderStatus"); DelayQueue<DelayTask> delayQueue = delayService.getDelayQueue(); //启动一个线程持续健康订单超时 Executors.newSingleThreadExecutor().execute(() -> { try { while (true) { if (delayQueue.size() > 0) { //容器中超时的订单记录会被取出 DelayTask delayTask = delayQueue.take(); //执行你的操作,如删除订单等 } } } catch (InterruptedException | QiniuException e) { log.error("InterruptedException error:", e); } }); } }
这是一个比较简单的实现方式, 不过最好有一个写入硬盘的操作, 如使用redis 或者MQ之类的中间件