DelayQueue简介
DelayQueue是juc包中的类,它表示的是一个无界的延迟队列,定义如下:
public class DelayQueue<E extends Delayed> extends AbstractQueue<E> implements BlockingQueue<E>;
DelayQueue存储的元素需要实现Delayed接口以实现优先级比较和延时取得。
DelayQueue还是一个阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部是延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,此时调用 poll() 将直接返回 null,调用 take() 将会发生阻塞,直到有元素发生到期,take() 才会返回。
当一个元素的 getDelay() 方法返回一个小于等于 0 的值时,将发生到期。
场景应用
下面将使用此类实现一个多考生考试的场景:
- 考试总时间为10秒,至少2秒后才可进行交卷。
- 考生可在2-10秒这段时间内的任意时间交卷。
- 考试时间一到,所有未交卷的学生必须交卷。
注:上述时间数据仅为测试方便使用,可根据实际情况进行修改
使用enum定义出时间常量:
enum Times {
SUMMIT_TIME(10), //考试总时间
SUMBMIT_LIMIT(2), // 交卷限制时间
MAX_RAND_TIME(15); // 模拟考生所需最大时间
private final int value;
private Times(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
定义学生类
基本定义:
class Student implements Delayed {
private String name;
private long delay; // 考试花费时间,单位为毫秒
private long expire; // 交卷时间,单位为毫秒
// 此构造可随机生成考试花费时间
public Student(String name) {
this.name = name;
this.delay = TimeUnit.MILLISECONDS.convert(getRandomSeconds(), TimeUnit.SECONDS);
this.expire = System.currentTimeMillis() + this.delay;
}
//此构造可指定考试花费时间
public Student(String name, long delay, TimeUnit unit) {
this.name = name;
this.delay = TimeUnit.MILLISECONDS.convert(delay, unit);
this.expire = System.currentTimeMillis() + this.delay;
}
// ...
}
利用Random获取学生考试花费时间:
public int getRandomSeconds() { // 获取随机花费时间,范围:2-10秒
return new Random().nextInt(Times.MAX_RAND_TIME.getValue() - Times.SUMBMIT_LIMIT.getValue())
+ Times.SUMBMIT_LIMIT.getValue();
}
覆写的compareTo()和getDelay()方法:
其中,getDelay()方法根据传入的TimeUnit返回剩余延时。比如,此元素还有2000毫秒延时期满、传入的参数为TimeUnit.SECONDS,那么返回值为2,即两秒。
@Override
public int compareTo(Delayed o) { // 此方法的实现用于定义优先级
long td = this.getDelay(TimeUnit.MILLISECONDS);
long od = o.getDelay(TimeUnit.MILLISECONDS);
return td > od ? 1 : td == od ? 0 : -1;
}
@Override
public long getDelay(TimeUnit unit) { // 这里返回的是剩余延时,当延时为0时,此元素延时期满,可从take()取出
return unit.convert(this.expire - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
主方法实现
-
初始化对象
DelayQueue<Student> queue = new DelayQueue<>();
-
添加测试数据
queue.add(new Student("范冰冰")); queue.add(new Student("成 龙")); queue.add(new Student("李一桐")); queue.add(new Student("宋小宝")); queue.add(new Student("吴 京")); queue.add(new Student("绿巨人")); queue.add(new Student("洪金宝")); queue.add(new Student("李云龙")); queue.add(new Student("钢铁侠")); queue.add(new Student("刘德华")); queue.add(new Student("戴安娜"));
-
添加一条用于考试结束时强制交卷的属性
queue.add(new Student("submit", Times.SUBMIT_TIME.getValue(),TimeUnit.SECONDS));
-
开始考试
while (true) { Student s = queue.take(); // 必要时进行阻塞等待 if (s.getName().equals("submit")) { System.out.println("时间已到,全部交卷!"); // 利用Java8 Stream特性使尚未交卷学生交卷 queue.parallelStream() .filter(v -> v.getExpire() >= s.getExpire()) .map(Student::submit) .forEach(System.out::println); System.exit(0); } System.out.println(s); }
输出样例
完整代码
package cn.gss.juc;
import java.text.DateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
enum Times {
SUBMIT_TIME(10), SUMBMIT_LIMIT(2), MAX_RAND_TIME(15);
private final int value;
private Times(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
/**
* DelayQueue实现多考生考试
* @author Gss
*/
public class TestDelayedQueue {
public static void main(String[] args) throws InterruptedException {
DelayQueue<Student> queue = new DelayQueue<>();
queue.add(new Student("范冰冰"));
queue.add(new Student("成 龙"));
queue.add(new Student("李一桐"));
queue.add(new Student("宋小宝"));
queue.add(new Student("吴 京"));
queue.add(new Student("绿巨人"));
queue.add(new Student("洪金宝"));
queue.add(new Student("李云龙"));
queue.add(new Student("钢铁侠"));
queue.add(new Student("刘德华"));
queue.add(new Student("戴安娜"));
queue.add(new Student("submit", Times.SUBMIT_TIME.getValue(), TimeUnit.SECONDS));
while (true) {
Student s = queue.take(); // 必要时进行阻塞等待
if (s.getName().equals("submit")) {
System.out.println("时间已到,全部交卷!");
// 利用Java8 Stream使尚未交卷学生交卷
queue.parallelStream()
.filter(v -> v.getExpire() >= s.getExpire())
.map(Student::submit)
.forEach(System.out::println);
System.exit(0);
}
System.out.println(s);
}
}
}
class Student implements Delayed {
private String name;
private long delay; // 考试花费时间,单位为毫秒
private long expire; // 交卷时间,单位为毫秒
// 此构造可随机生成考试花费时间
public Student(String name) {
this.name = name;
this.delay = TimeUnit.MILLISECONDS.convert(getRandomSeconds(), TimeUnit.SECONDS); // 随机生成考试花费时间
this.expire = System.currentTimeMillis() + this.delay;
}
// 此构造可指定考试花费时间
public Student(String name, long delay, TimeUnit unit) {
this.name = name;
this.delay = TimeUnit.MILLISECONDS.convert(delay, unit);
this.expire = System.currentTimeMillis() + this.delay;
}
public int getRandomSeconds() { // 获取随机花费时间
return new Random().nextInt(Times.MAX_RAND_TIME.getValue() - Times.SUMBMIT_LIMIT.getValue())
+ Times.SUMBMIT_LIMIT.getValue();
}
public Student submit() { // 设置花费时间和交卷时间,考试时间结束强制交卷时调用此方法
setDelay(Times.SUBMIT_TIME.getValue(), TimeUnit.SECONDS);
setExpire(System.currentTimeMillis());
return this;
}
public String getName() {
return name;
}
public long getExpire() {
return expire;
}
public void setDelay(long delay, TimeUnit unit) {
this.delay = TimeUnit.MILLISECONDS.convert(delay, TimeUnit.SECONDS);
}
public void setExpire(long expire) {
this.expire = expire;
}
@Override
public int compareTo(Delayed o) { // 此方法的实现用于定义优先级
long td = this.getDelay(TimeUnit.MILLISECONDS);
long od = o.getDelay(TimeUnit.MILLISECONDS);
return td > od ? 1 : td == od ? 0 : -1;
}
@Override
public long getDelay(TimeUnit unit) { // 这里返回的是剩余延时,当延时为0时,此元素延时期满,可从take()取出
return unit.convert(this.expire - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
@Override
public String toString() {
return "学生姓名:" + this.name + ",考试用时:" + TimeUnit.SECONDS.convert(delay, TimeUnit.MILLISECONDS) + ",交卷时间:"
+ DateFormat.getDateTimeInstance().format(new Date(this.expire));
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。