DelayQueue簡介
DelayQueue是一個無界阻塞隊列,只有在延遲期滿時,才能從中提取元素。
隊列的頭部,是延遲期滿后保存時間最長的delay元素。
在很多場景我們需要用到延時任務,比如給客戶異步轉賬操作超時后發通知告知用戶,還有客戶下單后多長時間內沒支付則取消訂單等等,這些都可以使用延時任務來實現。
jdk中DelayQueue可以實現上述需求,顧名思義DelayQueue就是延時隊列。
DelayQueue提供了在指定時間才能獲取隊列元素的功能,隊列頭元素是最接近過期的元素。
沒有過期元素的話,使用poll()方法會返回null值,超時判定是通過getDelay(TimeUnit.NANOSECONDS)方法的返回值小于等于0來判斷。
延時隊列不能存放空元素。
一般使用take()方法阻塞等待,有過期元素時繼續。
隊列元素說明
DelayQueue<E extends Delayed>的隊列元素需要實現Delayed接口,該接口類定義如下:
public interface Delayed extends Comparable<Delayed> { /** * Returns the remaining delay associated with this object, in the * given time unit. * * @param unit the time unit * @return the remaining delay; zero or negative values indicate * that the delay has already elapsed */ long getDelay(TimeUnit unit);}
所以DelayQueue的元素需要實現getDelay方法和Comparable接口的compareTo方法,getDelay方法來判定元素是否過期,compareTo方法來確定先后順序。
springboot中實例運用
DelayTask就是隊列中的元素
import java.util.Date;import java.util.concurrent.Delayed;import java.util.concurrent.TimeUnit;public class DelayTask implements Delayed { final private TaskBase data; final private long expire; /** * 構造延時任務 * @param data 業務數據 * @param expire 任務延時時間(ms) */ public DelayTask(TaskBase data, long expire) { super(); this.data = data; this.expire = expire + System.currentTimeMillis(); } public TaskBase getData() { return data; } public long getExpire() { return expire; } @Override public boolean equals(Object obj) { if (obj instanceof DelayTask) { return this.data.getIdentifier().equals(((DelayTask) obj).getData().getIdentifier()); } return false; } @Override public String toString() { return "{" + "data:" + data.toString() + "," + "expire:" + new Date(expire) + "}"; } @Override public long getDelay(TimeUnit unit) { return unit.convert(this.expire - System.currentTimeMillis(), unit); } @Override public int compareTo(Delayed o) { long delta = getDelay(TimeUnit.NANOSECONDS) - o.getDelay(TimeUnit.NANOSECONDS); return (int) delta; }}
TaskBase類是用戶自定義的業務數據基類,其中有一個identifier字段來標識任務的id,方便進行索引
import com.alibaba.fastjson.JSON;public class TaskBase { private String identifier; public TaskBase(String identifier) { this.identifier = identifier; } public String getIdentifier() { return identifier; } public void setIdentifier(String identifier) { this.identifier = identifier; } @Override public String toString() { return JSON.toJSONString(this); }}
新聞熱點
疑難解答