在實際的業務中會遇到如下場景:
1)過1分鐘失敗任務重試
2)過1小時發送郵件
等等,需要延時一段時間處理,在java的juc包中給我提供了DelayQueue延時隊列處理,過一會該處理的事兒。
DelayQueue<E extends Delayed>,一個無界阻塞隊列,只有在延遲期滿時才能從中提取元素。該隊列的頭部是延遲期滿後保存時間最長的Delayed元素。如果延遲都還沒有期滿,則隊列沒有頭部,並且 poll 將返回 null。當一個元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一個小於等於 0 的值時,將發生到期。即使無法使用 take 或 poll 移除未到期的元素,也不會將這些元素作爲正常元素對待。例如,size 方法同時返回到期和未到期元素的計數。此隊列不允許使用
null 元素。
下面通過代碼演示這一場景:
1.新建消息實現Delayed接口
package cn.slimsmart.study.queue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
/**
* 延時消息實體
* @author slimina
*
*/
public class Message implements Delayed{
private int id;
private String body; //消息內容
private long excuteTime;//執行時間
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public long getExcuteTime() {
return excuteTime;
}
public void setExcuteTime(long excuteTime) {
this.excuteTime = excuteTime;
}
public Message(int id, String body,long delayTime) {
this.id = id;
this.body = body;
this.excuteTime = TimeUnit.NANOSECONDS.convert(delayTime, TimeUnit.MILLISECONDS) + System.nanoTime();
}
@Override
public int compareTo(Delayed delayed) {
Message msg = (Message)delayed;
return Integer.valueOf(this.id)>Integer.valueOf(msg.id)?1:( Integer.valueOf(this.id)<Integer.valueOf(msg.id)?-1:0);
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(this.excuteTime - System.nanoTime(), TimeUnit.NANOSECONDS);
}
}
2.創建消費者
package cn.slimsmart.study.queue;
import java.util.concurrent.DelayQueue;
//消費者
public class Consumer implements Runnable {
// 延時隊列
private DelayQueue<Message> queue;
public Consumer(DelayQueue<Message> queue) {
this.queue = queue;
}
@Override
public void run() {
while (true) {
try {
Message take = queue.take();
System.out.println("消費消息:" + take.getId() + ":" + take.getBody());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3.向延時隊列發送消息
package cn.slimsmart.study.queue;
import java.util.concurrent.DelayQueue;
public class DelayQueueTest {
public static void main(String[] args) {
// 創建延時隊列
DelayQueue<Message> queue = new DelayQueue<Message>();
// 添加延時消息,m1 延時5s
Message m1 = new Message(1, "world", 3000);
// 添加延時消息,m2 延時3s
Message m2 = new Message(2, "hello", 10000);
queue.offer(m2);
queue.offer(m1);
// 啓動消費線程
new Thread(new Consumer(queue)).start();
}
}
運行可以看到消息接收的時間間隔。