您好,登錄后才能下訂單哦!
DelayQueue簡介
DelayQueue是一個(gè)無界阻塞隊(duì)列,只有在延遲期滿時(shí),才能從中提取元素。
隊(duì)列的頭部,是延遲期滿后保存時(shí)間最長的delay元素。
在很多場景我們需要用到延時(shí)任務(wù),比如給客戶異步轉(zhuǎn)賬操作超時(shí)后發(fā)通知告知用戶,還有客戶下單后多長時(shí)間內(nèi)沒支付則取消訂單等等,這些都可以使用延時(shí)任務(wù)來實(shí)現(xiàn)。
jdk中DelayQueue可以實(shí)現(xiàn)上述需求,顧名思義DelayQueue就是延時(shí)隊(duì)列。
DelayQueue提供了在指定時(shí)間才能獲取隊(duì)列元素的功能,隊(duì)列頭元素是最接近過期的元素。
沒有過期元素的話,使用poll()方法會(huì)返回null值,超時(shí)判定是通過getDelay(TimeUnit.NANOSECONDS)方法的返回值小于等于0來判斷。
延時(shí)隊(duì)列不能存放空元素。
一般使用take()方法阻塞等待,有過期元素時(shí)繼續(xù)。
隊(duì)列元素說明
DelayQueue<E extends Delayed>的隊(duì)列元素需要實(shí)現(xiàn)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的元素需要實(shí)現(xiàn)getDelay方法和Comparable接口的compareTo方法,getDelay方法來判定元素是否過期,compareTo方法來確定先后順序。
springboot中實(shí)例運(yùn)用
DelayTask就是隊(duì)列中的元素
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; /** * 構(gòu)造延時(shí)任務(wù) * @param data 業(yè)務(wù)數(shù)據(jù) * @param expire 任務(wù)延時(shí)時(shí)間(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類是用戶自定義的業(yè)務(wù)數(shù)據(jù)基類,其中有一個(gè)identifier字段來標(biāo)識(shí)任務(wù)的id,方便進(jìn)行索引
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); } }
定義一個(gè)延時(shí)任務(wù)管理類DelayQueueManager,通過@Component注解加入到spring中管理,在需要使用的地方通過@Autowire注入
import com.alibaba.fastjson.JSON; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.DelayQueue; import java.util.concurrent.Executors; @Component public class DelayQueueManager implements CommandLineRunner { private final Logger logger = LoggerFactory.getLogger(DelayQueueManager.class); private DelayQueue<DelayTask> delayQueue = new DelayQueue<>(); /** * 加入到延時(shí)隊(duì)列中 * @param task */ public void put(DelayTask task) { logger.info("加入延時(shí)任務(wù):{}", task); delayQueue.put(task); } /** * 取消延時(shí)任務(wù) * @param task * @return */ public boolean remove(DelayTask task) { logger.info("取消延時(shí)任務(wù):{}", task); return delayQueue.remove(task); } /** * 取消延時(shí)任務(wù) * @param taskid * @return */ public boolean remove(String taskid) { return remove(new DelayTask(new TaskBase(taskid), 0)); } @Override public void run(String... args) throws Exception { logger.info("初始化延時(shí)隊(duì)列"); Executors.newSingleThreadExecutor().execute(new Thread(this::excuteThread)); } /** * 延時(shí)任務(wù)執(zhí)行線程 */ private void excuteThread() { while (true) { try { DelayTask task = delayQueue.take(); processTask(task); } catch (InterruptedException e) { break; } } } /** * 內(nèi)部執(zhí)行延時(shí)任務(wù) * @param task */ private void processTask(DelayTask task) { logger.info("執(zhí)行延時(shí)任務(wù):{}", task); //根據(jù)task中的data自定義數(shù)據(jù)來處理相關(guān)邏輯,例 if (task.getData() instanceof XXX) {} } }
DelayQueueManager實(shí)現(xiàn)了CommandLineRunner接口,在springboot啟動(dòng)完成后就會(huì)自動(dòng)調(diào)用run方法。
總結(jié)
以上所述是小編給大家介紹的springboot執(zhí)行延時(shí)任務(wù)DelayQueue的使用詳解,希望對(duì)大家有所幫助,如果大家有任何疑問請給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)億速云網(wǎng)站的支持!
如果你覺得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請注明出處,謝謝!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。