Java之集合(十八)DelayQueue
转载请注明源出处: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的更多相关文章
- Java进阶(三十八)快速排序
Java进阶(三十八)快速排序 前言 有没有既不浪费空间又可以快一点的排序算法呢?那就是"快速排序"啦!光听这个名字是不是就觉得很高端呢. 假设我们现在对"6 1 2 7 ...
- Java IO(十八) BufferedReader 和 BufferedWriter
Java IO(十八) BufferedReader 和 BufferedWriter 一.介绍 BufferedReader 和 BufferedWriter 是字符缓冲流,分别继承自 Reader ...
- 王颖奇 201771010129《面向对象程序设计Java》第十八周实验总结
实验十八 总复习 实验时间 2018-12-30 1.实验目的与要求 (1) 综合掌握java基本程序结构: (2) 综合掌握java面向对象程序设计特点: (3) 综合掌握java GUI 程序设 ...
- Java基础(十八)集合(5)Queue集合
队列是只能在尾部添加元素,同时只能在头部删除元素的数据结构.队列的原则就是“先进先出”. Queue接口是Collection接口的最后一个子接口. Queue接口是队列接口,而Deque接口是Que ...
- Java并发(十八):阻塞队列BlockingQueue
阻塞队列(BlockingQueue)是一个支持两个附加操作的队列. 这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空.当队列满时,存储元素的线程会等待队列可用. 阻塞队列常用于生产 ...
- java提高篇(十八)-----数组之一:认识JAVA数组
噢,它明白了,河水既没有牛伯伯说的那么浅,也没有小松鼠说的那么深,只有自己亲自试过才知道!道听途说永远只能看到表明现象,只有亲自试过了,才知道它的深浅!!!!! 一.什么是数组 ...
- Java笔记(二十八)……IO流下 IO包中其他常用类以及编码表问题
PrintWriter打印流 Writer的子类,既可以接收字符流,也可以接收字节流,还可以接收文件名或者文件对象,非常方便 同时,还可以设置自动刷新以及保持原有格式写入各种文本类型的print方法 ...
- 夯实Java基础(十八)——泛型
1.什么是泛型 泛型是Java1.5中出现的新特性,也是最重要的一个特性.泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类. ...
- java基础(十八)IO流(一)
这里有我之前上课总结的一些知识点以及代码大部分是老师讲的笔记 个人认为是非常好的,,也是比较经典的内容,真诚的希望这些对于那些想学习的人有所帮助! 由于代码是分模块的上传非常的不便.也比较多,讲的也是 ...
随机推荐
- python小练习--属性
箭头这个作业: class Box:#定义一个类名为Box,类名后不必有括号,类包含类属性和类方法,这个类没有定义类属性 '''这是一个计算体积的类'''#这是这个类的__doc__属性,执行类后就可 ...
- python 按行读取判断是否为空
for line in fr.readlines(): try: # print(len(line)) if(len(line)==1): continue else: fw.write(matche ...
- python按行读取并替换
fp = open(''test2.txt','w') #打开你要写得文件test2.txt lines = open('test1.txt').readlines() #打开文件,读入每一行 f ...
- Nvidia显卡驱动下载
https://www.nvidia.cn/Download/index.aspx?lang=cn https://blog.csdn.net/weixin_39643690/article/deta ...
- (KMP Next的运用) Period II -- fzu -- 1901
http://acm.fzu.edu.cn/problem.php?pid=1901 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=703 ...
- Hdu1361&&Poj1068 Parencodings 2017-01-18 17:17 45人阅读 评论(0) 收藏
Parencodings Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other) Total ...
- Android DalivkVM与JVM的比较
JVM 与 DalivkVM的区别 Android 为什么还有搞一个Dalivk虚拟机,不是已经就有Java虚拟机了吗,为什么还要专门搞一个Dalivk虚拟机呢? 答: 1.以前Java是Sun公司的 ...
- mac下的抓包工具 -- Charles
# 背景 换了mac电脑,
- jenkins调用本地搭建sendmail邮件服务器发送邮件
应用jenkins发送邮件的邮件服务器 SMTP server 可以是本地的,也可以是远程,远程的就不多说了,在此说一下如何在jenkins本地服务器上搭建邮件服务器,并用jenkins发送邮件,详细 ...
- Microsoft Sql Server 2016安装在CentOS7下
安装过程 如何安装直接参考这个文章:安装sql server 整个安装过程非常简单. 上面的文档里是通过 sudo 命令,用root身份来执行,不过这里为了简单,就用root账号来安装的. (1)下载 ...