延迟队列实现30分钟订单自动过期失效

有一天,公司项目需求让用户订单未支付超过30分钟,自动取消订单状态.
我仔细想想用定时器?每分钟跑一下?显然不够优雅.
旁边同事看到我焦头烂额,有没有任何思绪.
突然扔给我两个文件,即高效又优雅的解决了我的问题,
我如获至宝,现在分享给大家.

1.首先Order实体类得实现Delayed接口

public class TjOrder implements Delayed, Serializable {
// ....省略好多字段

/**
* 传入进来排序的实例
*/
@Override
public int compareTo(Delayed o) {
if (this == o) {
return 0;
}
TjOrder order= (TjOrder) o;
long time = this.createTime.getTime() - order.getCreateTime().getTime();
return time == 0 ? 0 : time < 0 ? -1 : 1;
}

/**
* 取出处理过期订单
*/
@Override
public long getDelay(TimeUnit unit) {
// ORDER_TIME_OUT = 1800000L
return (this.createTime.getTime() + ConstantsUtil.ORDER_TIME_OUT) - System.currentTimeMillis();
}

/**
* 重写用于删除
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
TjOrder other = (TjOrder) obj;
if (other.getOrderNo() == null) {
return false;
} else if (!id.equals(other.getId())) {
return false;
} else if (!orderNo.equals(other.getOrderNo())) {
return false;
}
return true;
}
}

2.创建延迟服务类

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;

@Service
public class DelayService implements InitializingBean {

Logger logger = LoggerFactory.getLogger(this.getClass());
private static DelayQueue<TjOrder> delayQueue = new DelayQueue<TjOrder>();
private static AtomicBoolean start = new AtomicBoolean(false);
// 线程池
private static ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("useragent-pool-%d").build();
private static ExecutorService executorService = new ThreadPoolExecutor(
3, // 核心线程池大小
6, // 最大线程池大小
60L, // 线程最大空闲时间
TimeUnit.MILLISECONDS, // 时间单位(毫秒)
new LinkedBlockingQueue<Runnable>(), // 线程等待队列
threadFactory, // 线程创建工厂
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);


@Autowired
private TjOrderService tjOrderService;

@Override
public void afterPropertiesSet() throws Exception {
start();
}

public <T> void start() {
if (start.get()) {
return;
}
start.set(true);

//放入待付款订单
TjOrder order = new TjOrder();
// -1 未支付,常量池状态
order.setState(ConstantsUtil.ORDER_STATE_CREATE);
List<TjOrder> list = tjOrderService.getList(order);
list.forEach(item -> delayQueue.add(item));

executorService.submit(() -> {
// 取消订单
while (start.get()) {
try {
TjOrder order = delayQueue.take();
if (order != null) {
// 订单过期
TjOrder updateOrder = new TjOrder();
updateOrder.setId(order.getId());
// 常量池取消状态
updateOrder.setState(ConstantsUtil.ORDER_STATE_CANCEL);
tjOrderService.update(updateOrder);
// 还原
logger.info("=======订单号为[" + order.getOrderNo() + "]未支付过期,过期时间为:" + DateUtil.getNowStringTime() + "=======");
}
} catch (Exception e) {

}
}
});
}

public void add(TjOrder order) {
logger.info("加入订单队列订单号===={}", order.getOrderNo());
if (!start.get()) {
throw new RuntimeException("订单服务还未启动");
}
delayQueue.add(order);
}

public void delete(TjOrder order) {
if (!start.get()) {
throw new RuntimeException("订单服务还未启动");
}
delayQueue.remove(order);
}

public int getSize() {
if (!start.get()) {
throw new RuntimeException("订单服务还未启动");
}
return delayQueue.size();
}

}

3.使用

// 放入延迟队列
DelayService delayService = new DelayService();
delayService.add(order);