DelayQueue是一个无界阻塞队列,队列中的元素必须实现Delayed接口,在创建元素时可以指定多久才能从队列中获取当前元素。只有在延迟期满时才能从队列中提取元素。
DelayQueue可以用作缓存系统的设计,可以用DelayQueue保存缓存元素的有效期,使用一个线程循环查询DelayQueue,一旦能从DelayQueue中获取元素时,表示缓存有效期到了。
本文使用DelayQueue实现订单限时支付处理,以此加深对DelayQueue的理解。
实现Delayed接口,封装放入DelayQueue中的元素
@Getter
@Setter
@ToString
public class ItemVo<T> implements Delayed {
//超时时间
private long expireTime;
private T data;
public ItemVo(long expireTime, T data) {
this.expireTime = expireTime + System.currentTimeMillis();
this.data = data;
}
//用于获取到期剩余时间
public long getDelay(TimeUnit unit) {
long d = unit.convert(this.expireTime
- System.currentTimeMillis(), unit);
return d;
}
//按照剩余时间排序
public int compareTo(Delayed o) {
long d = (getDelay(TimeUnit.MILLISECONDS)
- o.getDelay(TimeUnit.MILLISECONDS));
if (d == 0) {
return 0;
} else {
if (d < 0) {
return -1;
} else {
return 1;
}
}
}
}
订单实体
@Getter
@Setter
@ToString
public class OrderEntity {
//订单金额
private double orderAmount;
//订单号
private String orderNo;
//0:未支付,1:已支付
private int orderStatus;
public OrderEntity(String orderNo, double orderAmount, int orderStatus) {
this.orderAmount = orderAmount;
this.orderNo = orderNo;
this.orderStatus = orderStatus;
}
}
启动三个线程,分别模拟生成订单、支付订单、处理订单超时
public class DelayOrder {
public static void main(String[] args) {
DelayQueue<ItemVo<OrderEntity>> delayQueue = new DelayQueue<>();
Map<String, OrderEntity> map = new ConcurrentHashMap<>();
//生成订单线程
new Thread(() -> {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//模拟订单号
long orderNo = 20200101000L;
while (true) {
try {
//随机等待一个时间后,再模拟生成一个订单
Thread.sleep(new Random().nextInt(10) * 1000);
//生成订单
OrderEntity orderEntity = new OrderEntity(String.valueOf(orderNo), new Random().nextInt(1000), 0);
//设置订单生成后10秒内未支付就超时。
ItemVo<OrderEntity> itemVo = new ItemVo<>(10 * 1000, orderEntity);
Date date = new Date();
date.setTime(itemVo.getExpireTime());
System.out.println("当前系统时间:" + simpleDateFormat.format(new Date()) +
", 生成一个订单,订单号:" + orderEntity.getOrderNo() +
", 订单金额:" + orderEntity.getOrderAmount() +
", 订单支付到期时间:" + simpleDateFormat.format(date));
//所有订单放入一个map容器中
map.put(String.valueOf(orderNo), orderEntity);
//订单号递增
orderNo++;
//放入延时队列
delayQueue.offer(itemVo);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
//模拟已经支付的订单
new Thread(() -> {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
while (true) {
try {
//随机等待一个时间后,再支付订单
Thread.sleep(new Random().nextInt(15) * 1000);
String orderNo = "";
Iterator<Map.Entry<String, OrderEntity>> iterator = map.entrySet().iterator();
if (iterator.hasNext()) {
OrderEntity orderEntity = iterator.next().getValue();
//设置订单状态为已支付
orderEntity.setOrderStatus(1);
orderNo = orderEntity.getOrderNo();
System.out.println("当前系统时间:" + simpleDateFormat.format(new Date()) + ", 有订单已经支付成功,订单号:" + orderNo +
", 订单金额:" + orderEntity.getOrderAmount());
}
//处理完从map中移除
map.remove(orderNo);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
//处理超时订单线程
new Thread(() -> {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
while (true) {
try {
//到期后从队列中取出
ItemVo<OrderEntity> itemVo = delayQueue.take();
Date date = new Date();
date.setTime(itemVo.getExpireTime());
OrderEntity orderEntity = itemVo.getData();
//处理超时未支付订单
if (orderEntity.getOrderStatus() == 0) {
System.out.println("有超时未支付的订单,订单号:" + orderEntity.getOrderNo() +
", 订单金额:" + orderEntity.getOrderAmount() +
", 订单支付到期时间:" + simpleDateFormat.format(date));
}
//处理完从map中移除
map.remove(orderEntity.getOrderNo());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
执行结果: