在业务开发中常常存在超时处理机制,比如订单多久没支付自动取消,命令执行太久自动取消执行之类。可以使用redis的key过期订阅机制,也可以使用rabbitmq的死信队列,亦或是循环轮训数据库等等来实现。在业务量小,无中间件的情况下,就可以考虑使用java原生的延时队列来实现,如下:
package com.example.quene;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
@Slf4j
public class DelayQuene {
public static final DelayQueue<DelayedOrder> DELAY_QUEUE = new DelayQueue<>();
@Data
public static class DelayedOrder implements Delayed {
private int index;
private long timeout;
public DelayedOrder(long timeout) {
this.timeout = timeout + System.nanoTime();
}
@Override
public int compareTo(Delayed other) {
if (other == this) {
return 0;
}
long d = (getDelay(TimeUnit.NANOSECONDS) - other.getDelay(TimeUnit.NANOSECONDS));
return (d == 0) ? 0 : ((d < 0) ? -1 : 1);
}
// 返回距离你自定义的超时时间还有多少
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(timeout - System.nanoTime(), TimeUnit.NANOSECONDS);
}
public void excute() {
log.info("第{}个订单已经到期未支付,自动取消", index);
}
}
public static void main(String[] args) {
for (int i = 1, len = 10; i <= len; i++) {
//延时队列放入10个订单,订单的过期时间分别为 1秒,2秒,3秒,4秒.......
DelayedOrder order = new DelayedOrder(TimeUnit.SECONDS.toNanos(i));
order.setIndex(i);
DELAY_QUEUE.put(order);
}
new Thread(new Runnable() {
@SneakyThrows
@Override
public void run() {
while (true) {
//阻塞方法,无订单过期时阻塞等待
DelayedOrder take = DELAY_QUEUE.take();
take.excute();
}
}
}).start();
}
}