文章目錄
[一] 簡介
註釋來自java api
Delayed 元素的一個無界阻塞隊列,只有在延遲期滿時才能從中提取元素。該隊列的頭部 是延遲期滿後保存時間最長的 Delayed 元素。如果延遲都還沒有期滿,則隊列沒有頭部,並且 poll 將返回 null。當一個元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一個小於等於 0 的值時,將發生到期。即使無法使用 take 或 poll 移除未到期的元素,也不會將這些元素作爲正常元素對待。例如,size 方法同時返回到期和未到期元素的計數。此隊列不允許使用 null 元素。
[二] DelayQueue 繼承體系
public class DelayQueue<E extends Delayed>extends AbstractQueue<E>implements BlockingQueue<E>
1. 核心方法
take()
獲取並移除此隊列的頭部,在可從此隊列獲得到期延遲的元素之前一直等待(如有必要)。
put(E)
將指定元素插入此延遲隊列。
offer(E)
將指定元素插入此延遲隊列。
poll()
獲取並移除此隊列的頭,如果此隊列不包含具有已到期延遲時間的元素,則返回 null。
peek()
獲取但不移除此隊列的頭部;如果此隊列爲空,則返回 null。
size()
返回此 collection 中的元素數。
clear()
自動移除此延遲隊列的所有元素。
[三] 使用 DelayQueue
準備 Delayed 的實現類
DelayQueue<E extends Delayed> 使用這個超時隊列, 根據他的泛型限制類型, 他所存儲的元素必須是 Delayed 這個接口的子類;
因此我們必須先構造一個這樣的子類, 假設有一個定時任務 Task, 在設定時間然後從隊列取出執行他.
定時任務 Task
/**
*
* 定時任務
*/
public class Task {
// 任務id
private Integer id;
// 任務名稱
private String name;
// 執行時間
private Long time;
public Task(Integer id, String name, Long time) {
this.id = id;
this.name = name;
this.time = time;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getTime() {
return time;
}
public void setTime(Long time) {
this.time = time;
}
@Override
public String toString() {
return "Task [id=" + id + ", name=" + name + ", time=" + new Date(time).toString() + "]";
}
}
Delayed 實現類:
因爲我們並不想改變 Task 的結構, 所以另外創建一個實現類 TaskDelayed
public class TaskDelayed implements Delayed {
// 任務
private Task task;
public TaskDelayed(Task task) {
super();
this.task = task;
}
public Task getTask() {
return task;
}
@Override
public int compareTo(Delayed o) {
return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
}
@Override
public long getDelay(TimeUnit unit) {
long time = task.getTime();
long currentTime = System.currentTimeMillis();
return unit.convert(time - currentTime, TimeUnit.MILLISECONDS);
}
}
1. 構造方法
BlockingQueue<TaskDelayed> queue = new DelayQueue<>();
put 與 take (一直阻塞直到完成操作爲止)
public static void main(String[] args) throws InterruptedException {
BlockingQueue<TaskDelayed> queue = new DelayQueue<>();
queue.put(new TaskDelayed(new Task(5, "ssss", System.currentTimeMillis() + 9000L)));
queue.put(new TaskDelayed(new Task(2, "ssss", System.currentTimeMillis() + 6000L)));
queue.put(new TaskDelayed(new Task(3, "ssss", System.currentTimeMillis() + 7000L)));
queue.put(new TaskDelayed(new Task(1, "ssss", System.currentTimeMillis() + 5000L)));
queue.put(new TaskDelayed(new Task(4, "ssss", System.currentTimeMillis() + 8000L)));
for(;;) {
System.out.println(queue.take().getTask() + "----" + new Date());
}
}
執行結果
Task [id=1, name=ssss, time=Wed Jan 23 14:09:12 CST 2019]----Wed Jan 23 14:09:12 CST 2019
Task [id=2, name=ssss, time=Wed Jan 23 14:09:13 CST 2019]----Wed Jan 23 14:09:13 CST 2019
Task [id=3, name=ssss, time=Wed Jan 23 14:09:14 CST 2019]----Wed Jan 23 14:09:14 CST 2019
Task [id=4, name=ssss, time=Wed Jan 23 14:09:15 CST 2019]----Wed Jan 23 14:09:15 CST 2019
Task [id=5, name=ssss, time=Wed Jan 23 14:09:16 CST 2019]----Wed Jan 23 14:09:16 CST 2019
這裏取出的時間和系統當前時間一致, 因爲我們指定了他取出的時間
關鍵方法在於 Delayed
public interface Delayed extends Comparable<Delayed> {
long getDelay(TimeUnit unit);
}
具體實現:
返回與此對象相關的剩餘延遲時間,以給定的時間單位表示。
@Override
public long getDelay(TimeUnit unit) {
long time = task.getTime();
long currentTime = System.currentTimeMillis();
return unit.convert(time - currentTime, TimeUnit.MILLISECONDS);
}