1、问题场景
大家应该都打过客服的电话,当客服忙的时候,你的电话会进入到排队状态,当然不会让你一直排队,会有个排队的超时时间。嫁入在这个超时时间内没有客服空闲出来,就会提示你要不要继续等待。这就有个问题,程序是怎么知道你的电话等待超时了呢?
这里就要用到延时队列了。
2、DelayQueue
DelayQueue 是 Delayed 元素的一个无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部 是延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,并且 poll 将返回 null。当一个元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一个小于等于 0 的值时,将发生到期。即无法使用 take 或 poll 移除未到期的元素,也不会将这些元素作为正常元素对待。例如,size 方法同时返回到期和未到期元素的计数。此队列不允许使用 null 元素。
放入DelayQueue的对象需要实现Delayed接口。
3、队列中的元素
package com.jeiao.redis;
import org.redisson.api.RQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
/**
* Author:ZhuShangJin
* Date:2018/8/31
*/
public class DelayedElement implements Delayed {
private final long delay; //你的电话要排队等的时间 比如你等了 60秒还没人接 这个就是等待时间 延迟时间
private final long expire; // 到期时间
private final String msg; //数据
private final long now; // 你的电话进入排队的时间 创建时间
public DelayedElement(long delay, String msg) {
this.delay = delay;
this.msg = msg;
expire = System.currentTimeMillis() + delay; //到期时间 = 当前时间+延迟时间
now = System.currentTimeMillis();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("DelayedElement{");
sb.append("delay=").append(delay);
sb.append(", expire=").append(expire);
sb.append(", msg='").append(msg).append('\'');
sb.append(", now=").append(now);
sb.append('}');
return sb.toString();
}
/**
* 需要实现的接口,获得延迟时间 用过期时间-当前时间
* @param unit
* @return
*/
public long getDelay(TimeUnit unit) {
return unit.convert(this.expire - System.currentTimeMillis() , TimeUnit.MILLISECONDS);
}
/**
* 用于延迟队列内部比较排序 当前时间的延迟时间 - 比较对象的延迟时间
* @param o
* @return
*/
public int compareTo(Delayed o) {
return (int) (this.getDelay(TimeUnit.MILLISECONDS) -o.getDelay(TimeUnit.MILLISECONDS));
}
}
4、测试代码
package com.jeiao.redis;
/**
* Author:ZhuShangJin
* Date:2018/8/31
*/
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
/**
*
*/
public class DelayQueueTest {
public static void main(String[] args) {
DelayQueue<DelayedElement> delayQueue = new DelayQueue<DelayedElement>();
//生产者
producer(delayQueue);
//消费者
consumer(delayQueue);
while (true){
try {
TimeUnit.HOURS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 每1000毫秒创建一个对象,放入延迟队列,延迟时间10000毫秒
* @param delayQueue
*/
private static void producer(final DelayQueue<DelayedElement> delayQueue){
new Thread(new Runnable() {
public void run() {
while (true){
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
DelayedElement element = new DelayedElement(10000,"test");
delayQueue.offer(element);
System.out.println("delayQueue size:"+delayQueue.size());
}
}
}).start();
}
/**
* 消费者,从延迟队列中获得数据,进行处理
* @param delayQueue
*/
private static void consumer(final DelayQueue<DelayedElement> delayQueue){
new Thread(new Runnable() {
public void run() {
while (true){
DelayedElement element = null;
try {
// 没有满足延时的元素 用poll返回 null
// 没有满足延时的元素 用take会阻塞
element = delayQueue.take();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis()+"---"+element);
}
}
}).start();
}
}