参考文章:https://mp.weixin.qq.com/s/vX2maaImVzvNjEOphBKzxQ
并发编程juc包学习5-DelayQueue延迟队列
延时队列学习
延时队列,首先,它是一种队列,队列意味着内部的元素是有序的,元素出队和入队是有方向性的,元素从一端进入,从另一端取出。
其次,延时队列,最重要的特性就体现在它的延时属性上,跟普通的队列不一样的是,普通队列中的元素总是等着希望被早点取出处理,而延时队列中的元素则是希望被在指定时间得到取出和处理,所以延时队列中的元素是都是带时间属性的,通常来说是需要被处理的消息或者任务。
总的来说:延时队列就是用来存放需要在指定时间被处理的元素的队列。
使用
场景:实现一个超时订单取消.
创建DelayQueue源码
public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
implements BlockingQueue<E>
队列中存放的数据必须要继承Delayed父类
那就写一个
超时订单类
class Order implements Delayed {
//订单创建时间
private long start = System.currentTimeMillis();
//订单id
public String id;
//订单过期时间间隔5s,不过现在用的单位是毫秒
private long delay = TimeUnit.MILLISECONDS.convert(5, TimeUnit.SECONDS);
//订单过期时间点
private long expire = start + delay;
public Order(String id) {
this.id = id;
}
@Override
//该方法必须小于等于0,才会认定是失效了.不能只返回一个过期时间,应该是(过期时间点-当前时间点)
public long getDelay(TimeUnit unit) {
return unit.convert(expire-System.currentTimeMillis(),TimeUnit.MILLISECONDS);
}
@Override
//用于在DelayQueue队列中排序.既然固定了过期时间,排序就没有意义了.只要保证快过期的在头部就行
//经测试只要返回一个大于0的数值即可
public int compareTo(Delayed o) {
return (int)(this.delay-o.getDelay(TimeUnit.MILLISECONDS));
}
@Override
public String toString() {
return this.id + "达到了过期时间" + new SimpleDateFormat("HH:mm:ss").format(new Date(this.expire));
}
}
订单处理类
延时队列的本质就是到点后就会移至队头。
DelayQueue本质是使用PriorityQueue(优先级队列)实现的
必须在DelayQueue中主动的去移除队头元素
public class TestDelayQueue {
public static void main(String[] args) throws InterruptedException {
//当中的元素必须实现Delayed接口 DelayQueue<E extends Delayed>
DelayQueue<Order> queue = new DelayQueue<>();
//异步线程,每2秒钟写一个订单
new Thread(()->{
for (int i = 0; i < 10; i++) {
Order order = new Order("订单==" + i);
queue.add(order);
System.out.println(order.id+"加入队列,---时间:"+new SimpleDateFormat("HH:mm:ss").format(new Date()));
//每2秒一个
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
//使主线程在移除过期的订单时保证当前队列不为空
TimeUnit.SECONDS.sleep(5);
while (true) {
//为了结束程序,当然也可以不要
if (queue.isEmpty()) {
break;
}
//取出队头元素,当到了过期时间,该订单就到了队头,只有移除之后size才能是0
Order order = queue.take();
System.out.println(order);
TimeUnit.MILLISECONDS.sleep(500);
}
System.out.println("此时的队列大小"+queue.size());
}
}
测试
达到过期时间之后会将队头的元素移除.直到队列是空为止.
订单==0加入队列,---时间:10:56:50
订单==1加入队列,---时间:10:56:52
订单==2加入队列,---时间:10:56:54
订单==0达到了过期时间10:56:55
订单==3加入队列,---时间:10:56:56
订单==1达到了过期时间10:56:57
订单==4加入队列,---时间:10:56:58
订单==2达到了过期时间10:56:59
订单==5加入队列,---时间:10:57:00
订单==3达到了过期时间10:57:01
订单==6加入队列,---时间:10:57:02
订单==4达到了过期时间10:57:03
订单==7加入队列,---时间:10:57:04
订单==5达到了过期时间10:57:05
订单==8加入队列,---时间:10:57:06
订单==6达到了过期时间10:57:07
订单==9加入队列,---时间:10:57:08
订单==7达到了过期时间10:57:09
订单==8达到了过期时间10:57:11
订单==9达到了过期时间10:57:13
此时的队列大小0