Java延时队列DelayQueue的使用

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 delayQueue = new DelayQueue();


        //生产者
        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 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 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();
    }
}

 

你可能感兴趣的:(Java多线程)