转载请注明源出处:http://www.cnblogs.com/lighten/p/7493735.html

1.前言

  本章介绍阻塞队列DelayQueue,这是一个无界阻塞队列。其存储延时的元素,只有延时耗尽元素才能被取出。队列头元素就是最先耗尽延时的元素,如果没有元素耗尽延时,poll操作会返回null。同样的,该队列不允许空元素。针对延时的特性,可以用户定时任务,到达时间就能取出任务执行,设计有时效的缓存,超时就清除。

2.DelayQueue

2.1 数据结构

  该类的实现十分简单,可以说是站在其它类的肩膀上实现的。一个保证线程安全的锁,一个存储元素的优先队列,一个等待队列头元素的线程,一个触发条件。

  优先队列之前介绍过,队列头是比较器或元素自身的比较方法比较出来的最小元素。这个队列所有的元素都必须实现Delayed接口,其方法需要给出剩余的延时时间。Delayed接口又是实现Comparable接口,注意该优先队列就是使用这个方法进行对比的,所以Comparable的实现要借助Delayed接口的方法选出剩余延时小,才能保证使用正确。

2.2 基本操作

  放入一个Delayed元素:

  线程安全,先加锁,然后放入一个元素到优先队列中。尝试取出,如果还是它,头元素被替换了,需要重置等待头元素的线程,唤醒阻塞的线程。

  取出元素也先加锁,尝试取出,如果时间未到返回null,否则就取出。

  超时的poll方法,以纳秒计算等待时间。先加锁保证线程安全,无限循环取第一个元素,如果没取到并且等待时间耗尽,直接返回null,没耗尽等待时间就继续等,直到被可用条件唤醒,或等待超时自动唤醒。如果取到了第一个元素,还需要看其剩余时间是否够了,够了就直接返回。不够等待时间又耗尽了就返回null。如果剩余等待时间比元素满足条件时间要小或者是有线程在等待第一个元素,直接等下去,等完剩余时间。否则,当前线程就是等待头元素的线程,可以等到头元素,等待头元素的时间。

  整个类的实现并不难,leader线程感觉没什么作用,但是按照JDK的注释所说,这种领导跟随者模式可以最小化等待的时间。就是说leader线程可以等待下一个延时,其它线程需要无限等待。看代码其实也能明白,如果存在leader线程,一定是有一个线程在等待第一个元素,那么本线程就必须一直等,而拿到leader的线程,只需要等第一个元素剩余的延时就可以了。

3.使用例子

  定义一个Delayed接口实现类:

class DelayedObject implements Delayed {

	private long delay;
private long begin;
private int value; public DelayedObject(int value, long delaySecond) {
this.begin = System.nanoTime();
this.delay = delaySecond;
this.value = value;
} @Override
public int compareTo(Delayed o) {
return getDelay(TimeUnit.NANOSECONDS) > o.getDelay(TimeUnit.NANOSECONDS) ? 1 :
(getDelay(TimeUnit.NANOSECONDS) == o.getDelay(TimeUnit.NANOSECONDS) ? 0 : -1);
} @Override
public long getDelay(TimeUnit unit) {
return unit.convert(delay, TimeUnit.SECONDS) - System.nanoTime() + begin;
} public int getValue() {
return value;
}
}

  测试用例:

  @Test
public void test() {
long begin = System.currentTimeMillis();
DelayQueue<DelayedObject> queue = new DelayQueue<>();
new Thread(new Runnable() {
public void run() {
for(int i = 0; i < 10; i++) {
queue.offer(new DelayedObject(i, 9-i/2));
}
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
try {
while(true) {
DelayedObject object = queue.take();
if(object != null) {
System.out.println(Thread.currentThread().getName() + ":"+ object.getValue() + ",耗时:"
+ (System.currentTimeMillis()-begin)/1000);
} else {
break;
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"poll-1").start(); new Thread(new Runnable() {
@Override
public void run() {
try {
while(true) {
DelayedObject object = queue.take();
if(object != null) {
System.out.println(Thread.currentThread().getName() + ":"+ object.getValue() + ",耗时:"
+ (System.currentTimeMillis()-begin)/1000);
} else {
break;
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"poll-2").start();
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}

  测试结果:

  注意结果不一定和上图相同。取出顺序和System.out的顺序不一定一致,上面的结果是一个较符合顺序的结果。

Java之集合(十八)DelayQueue的更多相关文章

  1. Java进阶(三十八)快速排序

    Java进阶(三十八)快速排序 前言 有没有既不浪费空间又可以快一点的排序算法呢?那就是"快速排序"啦!光听这个名字是不是就觉得很高端呢. 假设我们现在对"6 1 2 7 ...

  2. Java IO(十八) BufferedReader 和 BufferedWriter

    Java IO(十八) BufferedReader 和 BufferedWriter 一.介绍 BufferedReader 和 BufferedWriter 是字符缓冲流,分别继承自 Reader ...

  3. 王颖奇 201771010129《面向对象程序设计Java》第十八周实验总结

    实验十八  总复习 实验时间 2018-12-30 1.实验目的与要求 (1) 综合掌握java基本程序结构: (2) 综合掌握java面向对象程序设计特点: (3) 综合掌握java GUI 程序设 ...

  4. Java基础(十八)集合(5)Queue集合

    队列是只能在尾部添加元素,同时只能在头部删除元素的数据结构.队列的原则就是“先进先出”. Queue接口是Collection接口的最后一个子接口. Queue接口是队列接口,而Deque接口是Que ...

  5. Java并发(十八):阻塞队列BlockingQueue

    阻塞队列(BlockingQueue)是一个支持两个附加操作的队列. 这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空.当队列满时,存储元素的线程会等待队列可用. 阻塞队列常用于生产 ...

  6. java提高篇(十八)-----数组之一:认识JAVA数组

          噢,它明白了,河水既没有牛伯伯说的那么浅,也没有小松鼠说的那么深,只有自己亲自试过才知道!道听途说永远只能看到表明现象,只有亲自试过了,才知道它的深浅!!!!! 一.什么是数组      ...

  7. Java笔记(二十八)……IO流下 IO包中其他常用类以及编码表问题

    PrintWriter打印流 Writer的子类,既可以接收字符流,也可以接收字节流,还可以接收文件名或者文件对象,非常方便 同时,还可以设置自动刷新以及保持原有格式写入各种文本类型的print方法 ...

  8. 夯实Java基础(十八)——泛型

    1.什么是泛型 泛型是Java1.5中出现的新特性,也是最重要的一个特性.泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类. ...

  9. java基础(十八)IO流(一)

    这里有我之前上课总结的一些知识点以及代码大部分是老师讲的笔记 个人认为是非常好的,,也是比较经典的内容,真诚的希望这些对于那些想学习的人有所帮助! 由于代码是分模块的上传非常的不便.也比较多,讲的也是 ...

随机推荐

  1. 20. Dog,Man's Best Friend 狗,人类最好的朋友

    . Dog,Man's Best Friend 狗,人类最好的朋友 ①The dogs has always been considered man's best friend.Always note ...

  2. UVa 11210 Chinese Mahjong (暴力,递归寻找)

    题意:这个题意.有点麻烦,就是说给定13张牌,让你求能“听”的牌.(具体的见原题) 原题链接: https://uva.onlinejudge.org/index.php?option=com_onl ...

  3. java 路径、className.class.getResourceAsStream()、ClassLoader.getSystemResourceAsStream() 、FileInputStream

    className.class.getResourceAsStream 用法: 第一: 要加载的文件和.class文件在同一目录下,例如:com.x.y 下有类Test.class ,同时有资源文件c ...

  4. Getting Started with Google Tango(Google Tango开始教程)

    https://developers.google.com/tango/ Build apps that understand space and motion in high fidelity on ...

  5. web api解决序列化后返回标准时间带T问题

    添加类: public class JsonDataTimeConverter:IsoDateTimeConverter     {        public JsonDataTimeConvert ...

  6. Win7_Ultimate + VS2010 + openGL_MFC单文档应用开发框架搭建步骤

    Win7_Ultimate + VS2010 + openGL单文档应用开发框架搭建步骤 上一个配置是基于OpenGL的开发工具配置的,下面就是基于Vs2010的MFC单文档应用开发. 通过网上查找资 ...

  7. (原创)hibernate 一对多建表实例详解 附上各个注释的含义

    这个是hibernate的一对多建表实例:一的一端是部门(Department),对的一端是员工(Employee),下面贴上成员源代码:其中@mappedBy是加在@OneToMany一端,并且它的 ...

  8. hsweb 企业后台管理基础框架

    hsweb 详细介绍 业务功能 现在: 权限管理: 权限资源-角色-用户. 配置管理: kv结构,自定义配置.可通过此功能配置数据字典. 脚本管理: 动态脚本,支持javascript,groovy, ...

  9. 项目笔记---事半功倍之StyleCop(一)

    前言 曾几何时,你是否在看别人代码的时候总是在抱怨代码没有注释,命名不规范,代码风格不统一,代码可读性差?是否有一个适合团队开发规范的检查工具? 答案就是大名鼎鼎的StyleCop代码检查插件,有了这 ...

  10. LeetCode141:Linked List Cycle

    题目: Given a linked list, determine if it has a cycle in it. Follow up: Can you solve it without usin ...