DelayQueue简单介绍
DelayQueue:一个使用优先级队列实现的无界阻塞队列。
支持延时获取的元素的阻塞队列,元素必须要实现Delayed接口。
适用场景:实现自己的缓存系统,订单到期,限时支付等等。
具体代码会有注释,很好理解!
这里我们模拟一个订单延时处理的demo
首先我们定义一个订单实体类
/**
* 订单实体类
* @author James Lee
*
*/
public class Order {
// 订单编号
private String orderId;
// 订单金额
private Double orderMoney;
// 省略get、set等方法
}
创建存到队列里的元素
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
/**
* 存到队列里的元素
* 支持延时获取的元素的阻塞队列,元素必须要实现Delayed接口。
* 根据订单有效时间作为队列的优先级
* @param <T>
*/
public class ItemVo<T> implements Delayed{
// 到期时间 单位:ms
private long activeTime;
// 订单实体(使用泛型是因为后续扩展其他业务共用此业务类)
private T data;
public ItemVo(long activeTime, T data) {
super();
// 将传入的时间转换为超时的时刻
this.activeTime = TimeUnit.NANOSECONDS.convert(activeTime, TimeUnit.MILLISECONDS)
+ System.nanoTime();
this.data = data;
}
public long getActiveTime() {
return activeTime;
}
public T getData() {
return data;
}
// 按照剩余时间进行排序
@Override
public int compareTo(Delayed o) {
// 订单剩余时间-当前传入的时间= 实际剩余时间(单位纳秒)
long d = getDelay(TimeUnit.NANOSECONDS) - o.getDelay(TimeUnit.NANOSECONDS);
// 根据剩余时间判断等于0 返回1 不等于0
// 有可能大于0 有可能小于0 大于0返回1 小于返回-1
return (d == 0) ? 0 : ((d > 0) ? 1 : -1);
}
// 获取剩余时间
@Override
public long getDelay(TimeUnit unit) {
// 剩余时间= 到期时间-当前系统时间,系统一般是纳秒级的,所以这里做一次转换
long d = unit.convert(activeTime-System.nanoTime(), TimeUnit.NANOSECONDS);
return d;
}
}
创建订单生成类
import java.util.concurrent.DelayQueue;
/**
* 模拟订单插入的功能
*/
public class PutOrder implements Runnable {
// 使用DelayQueue:一个使用优先级队列实现的无界阻塞队列。
private DelayQueue<ItemVo<Order>> queue;
public PutOrder(DelayQueue<ItemVo<Order>> queue) {
super();
this.queue = queue;
}
@Override
public void run() {
/**
* 这里模拟淘宝、京东、苏宁的订单,淘宝是5秒到期,京东是10秒到期,苏宁是15秒到期
*/
// 淘宝订单插入
Order tbOrder = new Order("tb001", 9.9);
ItemVo<Order> itemVoTb = new ItemVo<Order>(5000, tbOrder);
queue.offer(itemVoTb);
System.out.println("淘宝订单5秒后过期:" + tbOrder.getOrderId());
// 京东订单插入
Order jdOrder = new Order("jd002", 19.9);
ItemVo<Order> itemVoJd = new ItemVo<Order>(10000, jdOrder);
queue.offer(itemVoJd);
System.out.println("京东订单10秒后过期:" + jdOrder.getOrderId());
// 苏宁订单插入
Order snOrder = new Order("sn003", 29.9);
ItemVo<Order> itemVoSn = new ItemVo<Order>(15000, snOrder);
queue.offer(itemVoSn);
System.out.println("苏宁订单15秒后过期:" + tbOrder.getOrderId());
}
}
创建订单过期取出类
import java.util.concurrent.DelayQueue;
/**
* 取出到期的订单的功能
*/
public class FetchOrder implements Runnable{
// 使用DelayQueue:一个使用优先级队列实现的无界阻塞队列。
private DelayQueue<ItemVo<Order>> queue;
public FetchOrder(DelayQueue<ItemVo<Order>> queue) {
super();
this.queue = queue;
}
@Override
public void run() {
while(true) {
try {
// 使用DelayQueue的take方法获取当前队列里的元素(take方法是阻塞方法,如果队列里有值则取出,否则一直阻塞)
ItemVo<Order> itemVo = queue.take();
// 获取元素的实体对象,保险起见做一次强制转型
Order order = (Order)itemVo.getData();
System.out.println("订单:" + order.getOrderId()+ " 已过期!已从订单队列里剔除!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
测试代码
import java.util.concurrent.DelayQueue;
/**
* 测试
*/
public class Test {
public static void main(String[] args) throws InterruptedException {
DelayQueue<ItemVo<Order>> queue = new DelayQueue<ItemVo<Order>>();
// 插入订单
new Thread(new PutOrder(queue)).start();
// 取出过期订单的线程
new Thread(new FetchOrder(queue)).start();
// 为了看到效果,这里没个一秒打印一次时间,一共15秒,打印15次。
for (int i = 1; i <= 15; i++) {
Thread.sleep(1000);
System.out.println("========================="+ i);
}
}
}
测试结果
淘宝订单5秒后过期:tb001
京东订单10秒后过期:jd002
苏宁订单15秒后过期:tb001
=========================1
=========================2
=========================3
=========================4
订单:tb001 已过期!已从订单队列里剔除!
=========================5
=========================6
=========================7
=========================8
=========================9
订单:jd002 已过期!已从订单队列里剔除!
=========================10
=========================11
=========================12
=========================13
=========================14
订单:sn003 已过期!已从订单队列里剔除!
=========================15
结果分析