Java的延遲隊(duì)列之DelayQueue解讀
一、DelayQueue的定義
public class DelayQueue<E extends Delayed> extends AbstractQueue<E> implements BlockingQueue<E>
DelayQueue是一個(gè)無界的BlockingQueue,是線程安全的(無界指的是隊(duì)列的元素?cái)?shù)量不存在上限,隊(duì)列的容量會(huì)隨著元素?cái)?shù)量的增加而擴(kuò)容,阻塞隊(duì)列指的是當(dāng)隊(duì)列內(nèi)元素?cái)?shù)量為0的時(shí)候,試圖從隊(duì)列內(nèi)獲取元素的線程將被阻塞或者拋出異常)
以上是阻塞隊(duì)列的特點(diǎn),而延遲隊(duì)列還擁有自己如下的特點(diǎn):
DelayQueue中存入的必須是實(shí)現(xiàn)了Delayed接口的對象(Delayed定義了一個(gè)getDelay的方法,用來判斷排序后的元素是否可以從Queue中取出,并且Delayed接口還繼承了Comparable用于排序),插入Queue中的數(shù)據(jù)根據(jù)compareTo方法進(jìn)行排序(DelayQueue的底層存儲(chǔ)是一個(gè)PriorityQueue,PriorityQueue是一個(gè)可排序的Queue,其中的元素必須實(shí)現(xiàn)Comparable接口的compareTo方法),并通過getDelay方法返回的時(shí)間確定元素是否可以出隊(duì),只有小于等于0的元素(即延遲到期的元素)才能夠被取出
延遲隊(duì)列不接收null元素
二、DelayQueue的作用
延遲隊(duì)列的作用顯然就是用于執(zhí)行延時(shí)任務(wù),如:
- 淘寶訂單業(yè)務(wù):下單之后如果三十分鐘之內(nèi)沒有付款就自動(dòng)取消訂單。
- 餓了嗎訂餐通知:下單成功后60s之后給用戶發(fā)送短信通知。
- 關(guān)閉空閑連接。服務(wù)器中,有很多客戶端的連接,空閑一段時(shí)間之后需要關(guān)閉之。
- 緩存。緩存中的對象,超過了空閑時(shí)間,需要從緩存中移出。
- 任務(wù)超時(shí)處理。在網(wǎng)絡(luò)協(xié)議滑動(dòng)窗口請求應(yīng)答式交互時(shí),處理超時(shí)未響應(yīng)的請求等。
三、DelayQueue的實(shí)現(xiàn)
定義延遲隊(duì)列元素
public class OrderDelayTask implements Delayed {
private Long orderId;
private long delayTime;
public OrderDelayTask(Long orderId, long delayTime) {
this.orderId = orderId;
// 延遲時(shí)間加當(dāng)前時(shí)間
this.delayTime = System.currentTimeMillis() + delayTime;
}
// 獲取任務(wù)剩余時(shí)間
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(delayTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed o) {
return Long.compare(delayTime, ((OrderDelayTask) o).delayTime);
}
}
定義延遲隊(duì)列并交付容器管理
@Bean("orderDelayQueue")
public DelayQueue<OrderDelayTask> orderDelayQueue(){
return new DelayQueue<OrderDelayTask>();
}
使用延遲隊(duì)列
@Autowired
private DelayQueue<OrderDelayObject> orderDelayQueue;
//發(fā)起訂單下單的時(shí)候?qū)⒂唵窝菔緦ο蠓湃雘rderDelayQueue
orderDelayQueue.add(
new OrderDelayTask(
"123456", // 訂單id
30 * 60 * 1000, // 延遲時(shí)間:30分鐘
)
);
開啟線程處理延遲任務(wù)
@Component
public class DelayTaskRunner<OrderDelayTask> implements InitializingBean {
@Autowired
private DelayQueue<OrderDelayTask> orderDelayQueue;
@Override
public void afterPropertiesSet() throws Exception {
new Thread(() -> {
try {
while(true) {
OrderDelayTask task = orderDelayQueue.take();
// 當(dāng)隊(duì)列為null的時(shí)候,poll()方法會(huì)直接返回null, 不會(huì)拋出異常,但是take()方法會(huì)一直等待,因此會(huì)拋出一個(gè)InterruptedException類型的異常。(當(dāng)阻塞方法收到中斷請求的時(shí)候就會(huì)拋出InterruptedException異常)
Long orderId = task.getOrderId();
// 執(zhí)行業(yè)務(wù)
}
} catch (InterruptedException e) {
// 因?yàn)槭侵貙慠unnable接口的run方法,子類拋出的異常要小于等于父類的異常。而在Runnable中run方法是沒有拋異常的。所以此時(shí)是不能拋出InterruptedException異常。如果此時(shí)你只是記錄日志的話,那么就是一個(gè)不負(fù)責(zé)任的做法,因?yàn)樵诓东@InterruptedException異常的時(shí)候自動(dòng)的將是否請求中斷標(biāo)志置為了false。在捕獲了InterruptedException異常之后,如果你什么也不想做,那么就將標(biāo)志重新置為true,以便棧中更高層的代碼能知道中斷,并且對中斷作出響應(yīng)。
Thread.currentThread().interrupt();
}
}).start();
}
}
四、DelayQueue實(shí)現(xiàn)延時(shí)任務(wù)的優(yōu)缺點(diǎn)
使用DelayQueue實(shí)現(xiàn)延時(shí)任務(wù)非常簡單,而且簡便,全部都是標(biāo)準(zhǔn)的JDK代碼實(shí)現(xiàn),不用引入第三方依賴(不依賴redis實(shí)現(xiàn)、消息隊(duì)列實(shí)現(xiàn)等),非常的輕量級。
它的缺點(diǎn)就是所有的操作都是基于應(yīng)用內(nèi)存的,一旦出現(xiàn)應(yīng)用單點(diǎn)故障,可能會(huì)造成延時(shí)任務(wù)數(shù)據(jù)的丟失。如果訂單并發(fā)量非常大,因?yàn)镈elayQueue是無界的,訂單量越大,隊(duì)列內(nèi)的對象就越多,可能造成OOM的風(fēng)險(xiǎn)。所以使用DelayQueue實(shí)現(xiàn)延時(shí)任務(wù),只適用于任務(wù)量較小的情況。
到此這篇關(guān)于Java的延遲隊(duì)列之DelayQueue解讀的文章就介紹到這了,更多相關(guān)延遲隊(duì)列DelayQueue內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 詳解Java線程池隊(duì)列中的延遲隊(duì)列DelayQueue
- Java延遲隊(duì)列DelayQueue原理詳解
- Java中的延遲隊(duì)列DelayQueue詳細(xì)解析
- Java阻塞延遲隊(duì)列DelayQueue原理及使用詳解
- Java中的延遲隊(duì)列DelayQueue源碼解析
- JAVA中的延遲隊(duì)列DelayQueue應(yīng)用解析
- java并發(fā)中DelayQueue延遲隊(duì)列原理剖析
- Java的DelayQueue延遲隊(duì)列簡單使用代碼實(shí)例
- Java實(shí)現(xiàn)DelayQueue延遲隊(duì)列示例代碼
相關(guān)文章
MyBatis-Plus工具使用之EntityWrapper解析
這篇文章主要介紹了MyBatis-Plus工具使用之EntityWrapper解析,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
簡單了解java函數(shù)式編碼結(jié)構(gòu)及優(yōu)勢
這篇文章主要介紹了簡單了解java函數(shù)式編碼結(jié)構(gòu)及優(yōu)勢,本文將探討三種下一代 JVM 語言:Groovy、Scala 和 Clojure,比較并對比新的功能和范例,讓 Java 開發(fā)人員對自己近期的未來發(fā)展有大體的認(rèn)識(shí)。,需要的朋友可以參考下2019-06-06
Java中直接初始化HashMap的方法實(shí)現(xiàn)
在Java編程中,HashMap 是常用的數(shù)據(jù)結(jié)構(gòu),用于存儲(chǔ)鍵值對,有時(shí)我們需要在創(chuàng)建 HashMap 的同時(shí)就初始化一些固定的、不會(huì)改變的值,然而,Java并沒有像某些動(dòng)態(tài)語言那樣的直接字面量初始化語法,所以本文給大家介紹了Java中直接初始化HashMap的方法,需要的朋友可以參考下2025-06-06
Java8方法引用及構(gòu)造方法引用原理實(shí)例解析
這篇文章主要介紹了Java8方法引用及構(gòu)造方法引用原理實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
Spring中Service注入多個(gè)實(shí)現(xiàn)類的方法詳解
這篇文章主要介紹了Spring中Service注入多個(gè)實(shí)現(xiàn)類的方法詳解,Spring是一個(gè)開源的Java框架,用于構(gòu)建企業(yè)級應(yīng)用程序,它提供了許多功能,如依賴注入、面向切面編程、數(shù)據(jù)訪問、Web開發(fā)等,需要的朋友可以參考下2023-07-07
Springboot Session共享實(shí)現(xiàn)原理及代碼實(shí)例
這篇文章主要介紹了Springboot Session共享實(shí)現(xiàn)原理及代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08
里氏代換原則_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要為大家詳細(xì)介紹了里氏代換原則的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08

