DelayQueue队列详解

概述

DelayQueuejava.util.concurrent中提供的一个很有意思的类。本文将会对DelayQueue做一个介绍,然后列举应用场景。并且提供一个Delayed接口的实现和 Sample 代码。

DelayQueue是一个无界的BlockingQueue,用于放置实现了Delayed接口的对象,其中的对象只能在其到期时才能从队列中取走。这种队列是有序的,即队头对象的延迟到期时间最长。注意:不能将null元素放置到这种队列中。

Delayed,一种混合风格的接口,用来标记那些应该在给定延迟时间之后执行的对象。Delayed扩展了Comparable接口,比较的基准为延时的时间值,Delayed接口的实现类getDelay的返回值应为固定值(final)。DelayQueue内部是使用PriorityQueue实现的。

应用举例

DelayQueue阻塞队列在我们系统开发中也常常会用到,例如:缓存系统的设计,缓存中的对象,超过了空闲时间,需要从缓存中移出;任务调度系统,能够准确的把握任务的执行时间。我们可能需要通过线程处理很多时间上要求很严格的数据,如果使用普通的线程,我们就需要遍历所有的对象,一个一个的检查看数据是否过期等,首先这样在执行上的效率不会太高,其次就是这种设计的风格也大大的影响了数据的精度。一个需要12:00点执行的任务可能12:01才执行,这样对数据要求很高的系统有更大的弊端。由此我们可以使用DelayQueue

我们在网咖或者网吧上网时会用到一个网吧综合系统,其中有一个主要功能就是给每一位网民计时,用户充值一定金额会有相应的上网时常,这里我们用DelayQueue模拟实现一下:

DelayQueue存储网民(Wangmin类),每一个考生都有自己的名字和完成试卷的时间,Wangba线程对DelayQueue进行监控,从队列中取出到时间的网民执行下机操作。

实现了Delayed接口的网民类

public class Wangmin implements Delayed {  

    private String name;  
    //身份证  
    private String id;  
    //截止时间  
    private long endTime;  
    //定义时间工具类
    private TimeUnit timeUnit = TimeUnit.SECONDS;
      
    public Wangmin(String name,String id,long endTime){  
        this.name=name;  
        this.id=id;  
        this.endTime = endTime;  
    }  
      
    public String getName(){  
        return this.name;  
    }  
      
    public String getId(){  
        return this.id;  
    }  
      
    /** 
     * 用来判断是否到了截止时间 
     */  
    @Override  
    public long getDelay(TimeUnit unit) { 
        //return unit.convert(endTime, TimeUnit.MILLISECONDS) - unit.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
        return endTime - System.currentTimeMillis();
    }  
  
    /** 
     * 相互批较排序用 
     */  
    @Override  
    public int compareTo(Delayed delayed) {  
        Wangmin w = (Wangmin)delayed;  
        return this.getDelay(this.timeUnit) - w.getDelay(this.timeUnit) > 0 ? 1:0;  
    }    
}

网吧类

public class WangBa implements Runnable {  

    private DelayQueue queue = new DelayQueue();  
    
    public boolean yingye =true;  
    
    /**
     * 上机 
     */
    public void shangji(String name,String id,int money){  
        Wangmin man = new Wangmin(name, id, 1000 * money + System.currentTimeMillis());  
        System.out.println("网名"+man.getName()+" 身份证"+man.getId()+"交钱"+money+"块,开始上机...");  
        this.queue.add(man);  
    }  
    
    // 下机
    public void xiaji(Wangmin man){  
        System.out.println("网名"+man.getName()+" 身份证"+man.getId()+"时间到下机...");  
    }  
  
    @Override  
    public void run() {  
        while(yingye){  
            try {  
                Wangmin man = queue.take();  
                xiaji(man);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
      
    public static void main(String args[]){  
        try{  
            System.out.println("网吧开始营业");  
            WangBa siyu = new WangBa();  
            Thread shangwang = new Thread(siyu);  
            shangwang.start();  
              
            siyu.shangji("路人甲", "123", 1);  
            siyu.shangji("路人乙", "234", 10);  
            siyu.shangji("路人丙", "345", 5);  
        }  
        catch(Exception e){  
            e.printStackTrace();
        }  
  
    }  
}

源码分析

首先看一下DlayedQueue源码

public class DelayQueue extends AbstractQueue
implements BlockingQueue {

    private final transient ReentrantLock lock = new ReentrantLock();
    private final PriorityQueue q = new PriorityQueue();

    // ...

}

这是一小部分源码,从这段源码可以看出,DelayedQueue中处理的是实现Delayed接口的任务,DelayedQueue使用lock来实现线程同步,使用PriorityQueue来管理任务。那么Delayed接口是什么呢?

public interface Delayed extends Comparable {

    long getDelay(TimeUnit unit);
}

这是Delayed接口的官方注释,意思是:一个混合风格的接口,为创建给定延迟的任务。(翻译的不太好,请纠正);其中有两个重要的方法compareTo和getDelay,第一个是比较两个任务的延迟时间进行排序,第二个方法用来获取延迟时间。

priorityQueue是一种优先级队列,这里优先级就是延迟时间,也就是说进入队列的任务安装优先级进行排序,延迟时间最短的在队列前面,先被处理,也就是说,每次从队列中取出的任务都将是到期的任务。比如我们实现一个缓存,当某个key-value对超期了,我们就可以从队列前取出,然后进行销毁操作。

这里有一个实现缓存的例子,链接如下:
http://www.cnblogs.com/jobs/archive/2007/04/27/730255.html



作者:algernoon
链接:https://www.jianshu.com/p/5b48180bafce
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

你可能感兴趣的:(java并发编程)