DelayQueue基本简介

作者: OneXzgj | 来源:发表于2019-01-24 10:58 被阅读1次

    DelayQueue基本简介

    DelayQueue是一个无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部是延迟期满后保存时间最长的Delayed 元素。

    DelayQueue是一个用来延时处理的队列,所谓延时处理就是说可以为队列中元素设定一个过期时间,相关的操作受到这个设定时间的控制。

    DelayQueue使用场景

    1. 关闭空闲连接。服务器中,有很多客户端的连接,空闲一段时间之后需要关闭之。
    2. 缓存。缓存中的对象,超过了空闲时间,需要从缓存中移出。
    3. 任务超时处理。在网络协议滑动窗口请求应答式交互时,处理超时未响应的请求。

    如果不使用DelayQueue,那么常规的解决办法就是:使用一个后台线程,遍历所有对象,挨个检查。这种笨笨的办法简单好用,但是对象数量过多时,可能存在性能问题,检查间隔时间不好设置,间隔时间过大,影响精确度,过小则存在效率问题。而且做不到按超时的时间顺序处理。

    DelayQueue基本原理

    • 首先,这种队列中只能存放实现Delayed接口的对象,而此接口有两个需要实现的方法。最重要的就是getDelay,这个方法需要返回对象过期前的时间。简单说,队列在某些方法处理前,会调用此方法来判断对象有没有超时。

    • 其次,DelayQueue是一个BlockingQueue,其特化的参数是Delayed。(不了解BlockingQueue的同学,先去了解BlockingQueue再看本文)
      Delayed扩展了Comparable接口,比较的基准为延时的时间值,Delayed接口的实现类getDelay的返回值应为固定值(final)。DelayQueue内部是使用PriorityQueue实现的。

    • 总结,DelayQueue的关键元素BlockingQueue、PriorityQueue、Delayed。可以这么说,DelayQueue是一个使用优先队列(PriorityQueue)实现的BlockingQueue,优先队列的比较基准值是时间。本质上即:

    DelayQueue = BlockingQueue +PriorityQueue + Delayed

    基本定义如下
    public interface Comparable<T> {
        public int compareTo(T o);
    }
    
    public interface Delayed extends Comparable<Delayed> {
        long getDelay(TimeUnit unit);
    }
    
    public class DelayQueue<E extends Delayed> implements BlockingQueue<E> { 
        private final PriorityQueue<E> q = new PriorityQueue<E>();
    }
    
    DelayQueue内部的实现使用了一个优先队列。当调用DelayQueue的offer方法时,把Delayed对象加入到优先队列q中。如下:
    public boolean offer(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            E first = q.peek();
            q.offer(e);
            if (first == null || e.compareTo(first) < 0)
                available.signalAll();
            return true;
        } finally {
            lock.unlock();
        }
    }
    
    DelayQueue的take方法,把优先队列q的first拿出来(peek),如果没有达到延时阀值,则进行await处理。如下:
    public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            for (;;) {
                E first = q.peek();
                if (first == null) {
                    available.await();
                } else {
                    long delay =  first.getDelay(TimeUnit.NANOSECONDS);
                    if (delay > 0) {
                        long tl = available.awaitNanos(delay);
                    } else {
                        E x = q.poll();
                        assert x != null;
                        if (q.size() != 0)
                            available.signalAll(); // wake up other takers
                        return x;
    
                    }
                }
            }
        } finally {
            lock.unlock();
        }
    }
    

    相关文章

      网友评论

        本文标题:DelayQueue基本简介

        本文链接:https://www.haomeiwen.com/subject/pllyjqtx.html