关闭

DelayQueue原理分析

3076人阅读 评论(0) 收藏 举报
分类:

DelayQueue基本简介

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

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

DelayQueue使用场景

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

如果不使用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<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();
    }
}

-------------------

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:3378398次
    • 积分:22322
    • 等级:
    • 排名:第338名
    • 原创:40篇
    • 转载:808篇
    • 译文:0篇
    • 评论:235条
    最新评论