DelayQueue 队列
2016-05-24 16:18
417 查看
DelayQueue—-一种有序队列,特点就是只有在队列中的元素到期后才能取出。
1.内存中哪些对象到了超时时间,需要从内存中清除出去。
2.服务器连接中有哪些连接很长时间未操作,需要关闭这些连接
3.任务中有哪些到了执行时间,该进行调度了。
简单的方法就是写一个线程不断去检查每一项是否到了时间,但这种方法在队列中的元素非常多的情况下会不准确或太耗费性能,用DelayQueue可完美地解决这个问题。
马上就要过年了,每次回老家都要悲催地去镇上人挤人的网吧上网。下面就拿这个做个例子:
假设镇上开了一家无限大的网吧,每人交一块钱可以上一分钟网(过年时的网吧坑爹程度差不多就这样);
网吧比较老式没有先进的管理系统,为了知道哪个家伙时间到该下机了,老板得一台一台地去看,上网的人一多等老板把整个网吧转一遍有些家伙早超时了,而且老板要一遍一遍地检查也累个半死;
有一天某个人给老板开发了个简单的程序,这个程序可以自动将上机的人排序,并在恰当的时间告诉老板哪个家伙时间到了。这个程序大概会是这样:
网吧开始营业
检查ing
网名路人甲 身份证123交钱1块,开始上机…
网名路人乙 身份证234交钱2块,开始上机…
网名路人丙 身份证345交钱1块,开始上机…
网名路人甲 身份证123时间到下机…
检查ing
网名路人丙 身份证345时间到下机…
检查ing
网名路人乙 身份证234时间到下机…
检查ing
从上面的运行结果可以看出,程序并没有一遍一遍地扫描队列中的对象,而是在队列中没有对象符合条件时阻塞。
至于这个好不好用呢,用过才知道,尤其是在并发量比较大的情况下。
DelayQueue 的内部是一个优先队列,从数据结构上看是一个类有序二叉树:
offer、poll、remove() 和 add—— O(log(n)) 时间;
remove(Object) 和 contains(Object) ——线性时间;
peek、element 和 size——-固定时间
DelayQueue是一个BlockingQueue,其特化的参数是Delayed。(不了解BlockingQueue的同学,先去了解BlockingQueue再看本文)
Delayed扩展了Comparable接口,比较的基准为延时的时间值,Delayed接口的实现类getDelay的返回值应为固定值(final)。DelayQueue内部是使用PriorityQueue实现的。
DelayQueue = BlockingQueue + PriorityQueue + Delayed
DelayQueue的关键元素BlockingQueue、PriorityQueue、Delayed。可以这么说,DelayQueue是一个使用优先队列(PriorityQueue)实现的BlockingQueue,优先队列的比较基准值是时间。
1.内存中哪些对象到了超时时间,需要从内存中清除出去。
2.服务器连接中有哪些连接很长时间未操作,需要关闭这些连接
3.任务中有哪些到了执行时间,该进行调度了。
public class DelayQueue<E extends Delayed> extends AbstractQueue<E> implements BlockingQueue<E> { private transient final ReentrantLock lock = new ReentrantLock(); private final PriorityQueue<E> q = new PriorityQueue<E>(); 堆实现的 private Thread leader = null; private final Condition available = lock.newCondition(); 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) return q.poll(); else if (leader != null) available.await(); else { Thread thisThread = Thread.currentThread(); leader = thisThread; try { available.awaitNanos(delay); } finally { if (leader == thisThread) leader = null; } } } } } finally { if (leader == null && q.peek() != null) available.signal(); lock.unlock(); } }
简单的方法就是写一个线程不断去检查每一项是否到了时间,但这种方法在队列中的元素非常多的情况下会不准确或太耗费性能,用DelayQueue可完美地解决这个问题。
马上就要过年了,每次回老家都要悲催地去镇上人挤人的网吧上网。下面就拿这个做个例子:
假设镇上开了一家无限大的网吧,每人交一块钱可以上一分钟网(过年时的网吧坑爹程度差不多就这样);
网吧比较老式没有先进的管理系统,为了知道哪个家伙时间到该下机了,老板得一台一台地去看,上网的人一多等老板把整个网吧转一遍有些家伙早超时了,而且老板要一遍一遍地检查也累个半死;
有一天某个人给老板开发了个简单的程序,这个程序可以自动将上机的人排序,并在恰当的时间告诉老板哪个家伙时间到了。这个程序大概会是这样:
public class Wangming implements Delayed { private String name; //身份证 private String id; //截止时间 private long endTime; public Wangming(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) { // TODO Auto-generated method stub return endTime-System.currentTimeMillis(); } /** * 相互批较排序用 */ @Override public int compareTo(Delayed o) { // TODO Auto-generated method stub Wangming jia = (Wangming)o; return endTime-jia.endTime>0?1:0; } }
public class WangBa implements Runnable { private DelayQueue<Wangming> queue = new DelayQueue<Wangming>(); public boolean yinye =true; public void shangji(String name,String id,int money){ Wangming man = new Wangming(name,id,1000*60*money+System.currentTimeMillis()); System.out.println("网名"+man.getName()+" 身份证"+man.getId()+"交钱"+money+"块,开始上机..."); this.queue.add(man); } public void xiaji(Wangming man){ System.out.println("网名"+man.getName()+" 身份证"+man.getId()+"时间到下机..."); } @Override public void run() { // TODO Auto-generated method stub while(yinye){ try { System.out.println("检查ing"); Wangming man = queue.take(); xiaji(man); } catch (InterruptedException e) { // TODO Auto-generated catch block 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", 2); siyu.shangji("路人丙", "345", 1); } catch(Exception ex){ } } }
网吧开始营业
检查ing
网名路人甲 身份证123交钱1块,开始上机…
网名路人乙 身份证234交钱2块,开始上机…
网名路人丙 身份证345交钱1块,开始上机…
网名路人甲 身份证123时间到下机…
检查ing
网名路人丙 身份证345时间到下机…
检查ing
网名路人乙 身份证234时间到下机…
检查ing
从上面的运行结果可以看出,程序并没有一遍一遍地扫描队列中的对象,而是在队列中没有对象符合条件时阻塞。
至于这个好不好用呢,用过才知道,尤其是在并发量比较大的情况下。
DelayQueue 的内部是一个优先队列,从数据结构上看是一个类有序二叉树:
offer、poll、remove() 和 add—— O(log(n)) 时间;
remove(Object) 和 contains(Object) ——线性时间;
peek、element 和 size——-固定时间
DelayQueue是一个BlockingQueue,其特化的参数是Delayed。(不了解BlockingQueue的同学,先去了解BlockingQueue再看本文)
Delayed扩展了Comparable接口,比较的基准为延时的时间值,Delayed接口的实现类getDelay的返回值应为固定值(final)。DelayQueue内部是使用PriorityQueue实现的。
DelayQueue = BlockingQueue + PriorityQueue + Delayed
DelayQueue的关键元素BlockingQueue、PriorityQueue、Delayed。可以这么说,DelayQueue是一个使用优先队列(PriorityQueue)实现的BlockingQueue,优先队列的比较基准值是时间。
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>(); }
相关文章推荐
- Android UI开发推荐颜色
- 解决AndroidStudio导入项目在 Building gradle project info 一直卡住
- Change Column Name or Set Default Value in MySql
- ue4 rpc调用不起作用
- STL之priority_queue
- UiAutomator简单实例----进入Settings->Language&input
- PriorityQueue详解
- juey点击tr选中里面的radio
- STL之queue
- easyui1.32 各种问题汇总
- 模拟实现英汉字典(使用key/value形式的哈希表)
- 国产数据连接池Druid
- 虚幻4 改变默认UI Disable的Shader
- Django中嵌入ueditor并改进SyntaxHighlighter
- LinkIssue: Error 'LINK : fatal error LNK1123: failure during conversion to COFF: file invalid or cor
- 1017. Queueing at Bank (25)
- finished with non-zero exit value 2
- STL之deque
- KVC中setValuesForKeysWithDictionary:
- request threaded-only IRQs with IRQF_ONESHOT【转】