您好,登錄后才能下訂單哦!
本篇內容主要講解“Java DelayQueue怎么實現延時任務”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Java DelayQueue怎么實現延時任務”吧!
DelayQueue是一個無界的BlockingQueue的實現類,用于放置實現了Delayed接口的對象,其中的對象只能在其到期時才能從隊列中取走。
BlockingQueue即阻塞隊列,java提供的面向多線程安全的隊列數據結構,當隊列內元素數量為0的時候,試圖從隊列內獲取元素的線程將被阻塞或者拋出異常。
這里的“無界”隊列,是指隊列的元素數量不存在上限,隊列的容量會隨著元素數量的增加而擴容。
DelayQueue實現了BlockingQueue接口,所以具有無界、阻塞的特點,除此之外它自己的核心特點就是:
「放入該隊列的延時任務對象,只要到達延時時間之后才能被取到」。
DelayQueue 不接收null元素
「DelayQueue 只接受那些實現了java.util.concurrent.Delayed接口的對象」
了解了DelayQueue的特點之后,我們就可以利用它來實現延時任務了,實現java.util.concurrent.Delayed
接口。
import org.jetbrains.annotations.NotNull; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; /** * 延時訂單任務 */ public class OrderDelayObject implements Delayed { private String name; private long delayTime; //延時時間 //實際業務中這里傳訂單信息對象,我這里只做demo,所以使用字符串了 private String order; public OrderDelayObject(String name, long delayTime, String order) { this.name = name; //延時時間加上當前時間 this.delayTime = System.currentTimeMillis() + delayTime; this.order = order; } //獲取延時任務的倒計時時間 @Override public long getDelay(TimeUnit unit) { long diff = delayTime - System.currentTimeMillis(); return unit.convert(diff, TimeUnit.MILLISECONDS); } //延時任務隊列,按照延時時間元素排序,實現Comparable接口 @Override public int compareTo(@NotNull Delayed obj) { return Long.compare(this.delayTime, ((OrderDelayObject) obj).delayTime); } @Override public String toString() { Date date = new Date(delayTime); SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return "\nOrderDelayObject:{" + "name=" + name + ", time=" + sd.format(date) + ", order=" + order + "}"; } }
上文類中的order為訂單信息對象,在實際的業務開發過程中應該是傳遞訂單信息,用于取消訂單業務的實現(訂單30分鐘不付款自動取消)。
Delayed接口繼承自 Comparable接口,所以需要實現compareTo方法,用于延時任務在隊列中按照“延時時間”進行排序。
getDelay方法是Delayed接口方法,實現該方法提供獲取延時任務的倒計時時間
首先我們需要一個容器,永久保存延時任務隊列,如果是Spring開發環境我們可以這樣做。
@Bean("orderDelayQueue") public DelayQueue<OrderDelayObject> orderDelayQueue(){ return new DelayQueue<OrderDelayObject>(); }
當用戶下單的時候,將訂單下單任務放入延時隊列
@Resource private DelayQueue<OrderDelayObject> orderDelayQueue; //發起訂單下單的時候將訂單演示對象放入orderDelayQueue orderDelayQueue.add( new OrderDelayObject( "訂單延時取消任務", 30 * 60 * 1000, //延時30分鐘 "延時任務訂單對象信息" ) );
系統內開啟一個線程,不斷的從隊列中獲取消息,獲取到之后對延時消息進行處理。DelayQueue
的take方法從隊列中獲取延時任務對象,如果隊列元素數量為0,或者沒有到達“延時時間的任務”,該線程會被阻塞。
@Component public class DelayObjectConsumer implements InitializingBean { @Resource private DelayQueue<OrderDelayObject> orderDelayQueue; @Override public void afterPropertiesSet() throws Exception { while (true) { OrderDelayObject task = orderDelayQueue.take(); System.out.println(task.toString()); System.out.println(task.getOrder()); //根據order訂單信息,去查詢該訂單的支付信息 //如果用戶沒有進行支付,將訂單從數據庫中關閉 //如果訂單并發量比較大,這里可以考慮異步或線程池的方式進行處理 } } }
需要說明的是,這里的while-true循環的延時任務處理是順序執行的,在訂單并發量比較大的時候,需要考慮異步處理的方式完成訂單的關閉操作。我之前寫過一個SpringBoot的可觀測、易配置的線程池開源項目,可能會對你有幫助,源代碼地址
經過我的測試,放入orderDelayQueue的延時任務,在半小時之后得到正確的執行處理。說明我們的實現是正確的。
使用DelayQueue實現延時任務非常簡單,而且簡便,全部都是標準的JDK代碼實現,不用引入第三方依賴(不依賴redis實現、消息隊列實現等),非常的輕量級。
它的缺點就是所有的操作都是基于應用內存的,一旦出現應用單點故障,可能會造成延時任務數據的丟失。如果訂單并發量非常大,因為DelayQueue是無界的,訂單量越大,隊列內的對象就越多,可能造成OOM的風險。所以使用DelayQueue實現延時任務,只適用于任務量較小的情況。
到此,相信大家對“Java DelayQueue怎么實現延時任務”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。