DelayQueue原理分析

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();
    }
}

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

你可能感兴趣的:(Java,精华文章)