模拟一个场景,用户下单后迟迟未付款, 我们需要在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之类的中间件
|