深度解析延遲佇列DelayQueue

2021-10-01 13:45:29 字數 3560 閱讀 5523

有時候,我們有一些任務需要「稍後」來做,比如一些連線需要空閒一段時間後再關閉,session需要空閒一段時間後自動退出。這個時候就需要一些可以延遲執行任務的工具。delayqueue(延遲佇列)就是乙個可以實現類似功能的工具。

由於本篇會涉及到優先佇列priorityqueue,所以預先閱讀 深度解析優先順序佇列priorityqueue 很有必要。

delayqueue(延遲佇列)的標準實現出現在jdk1.5中的j.u.c包中,作為乙個工具類,用來管理一些需要延遲處理的任務。先來看下它的類體系結構:

需要注意的是delayqueue實現了blockingqueue介面,意味著它也是阻塞佇列,但是類名稱中沒有包含blocking

因為delayqueue比一般佇列使用起來稍微複雜一定,所以先看乙個例項:

/**

* @author sicimike

*/public class delayqueuedemo catch (interruptedexception e) }}

}

其中佇列內部元素delayobject定義如下:

/**

* 延遲佇列中的元素

* 必須實現delayed介面

* @author sicimike

*/class delayobject implements delayed

@override

public int compareto(delayed o)

public delayobject()

public delayobject(string id, long destroytime)

public long getdestroytime()

public void setdestroytime(long destroytime)

public string getid()

public void setid(string id)

@override

public string tostring() ';}}

執行結果:

1576763926966 -> 入隊完成

1576763929959 -> delayobject

1576763932959 -> delayobject

1576763934961 -> delayobject

從執行結果可以看出,三個元素入隊完成後,大概延遲了3秒,出隊了第乙個元素;繼續延遲3秒,出隊第二個元素;繼續延遲2秒,出隊第三個元素。

元素的出隊順序與放入的順序無關,而與元素延遲的時間有關,按照公升序排列出隊,順序由delayobject中的compareto方法決定。

放入delayqueue中的元素必須實現delayed介面,實現介面中的getdelay方法和compareto方法。getdelay獲取的是元素剩餘的時間,所以不同的時刻呼叫該方法,應該得到不同的值,否則元素永遠不會過期。compareto方法用於給元素排序,排在前面的先出隊。

這就是延遲佇列delayqueue的基本使用。

大致了解delayqueue的使用後,再來看下delayqueue是如何實現的。首先就要看它的類定義和成員變數

public class delayqueueextends abstractqueueimplements blockingqueue
根據定義可以看出底層通過組合的方式持有優先佇列priorityqueue的物件,也就是說延遲佇列delayqueue底層是通過優先佇列priorityqueue來實現的。

需要重點關注的核心操作只有三個:入隊出隊檢視隊首元素

offer(e e)方法用於往delayqueue中放入元素。由於delayqueue是無界佇列(底層priorityqueue可以自動擴容),所以往delayqueue中放入元素是非阻塞的。putadd均是呼叫offer方法,其實現如下:

public void put(e e) 

public boolean add(e e)

public boolean offer(e e, long timeout, timeunit unit)

// 真正完成入隊操作的方法

public boolean offer(e e)

return true;

} finally

}

take()方法以阻塞的方式從delayqueue中取出乙個元素。

public e take() throws interruptedexception  finally }}

}} finally

}

通過take方法可以看出delayqueue使用reentrantlock+condition來實現執行緒的阻塞、喚醒。再加上迴圈,如果隊首元素不出隊,執行緒會一直被阻塞。

這裡的leader使用的是leader/follower模型,隊首元素尚未出隊時,leader不為null。其餘的執行緒知道leader不為null之後就被無限阻塞;隊首元素出隊後,leader為null,通知其餘的執行緒來爭搶。

delayqueue實現了blockingqueue介面,是阻塞佇列。底層利用了優先佇列priorityqueue的自動擴容、排序等機制。再利用reentrantlock+condition機制實現執行緒安全,以及執行緒休眠、喚醒。

深度解析佇列操作

大家都知道,佇列是一種特殊的線性表,是運算受到限制的一種線性表,只允許在表的一端進行插入,而在另一端進行刪除元素的線性表。隊尾 tail 是允許插入的一端。隊頭 head 是允許刪除的一端。空佇列是不含元素的空表。根據這樣的操作。佇列特點是先進先出 通過此篇,你將會深入了解到佇列的基本操作,便於以後...

Rabbitmq延遲佇列

建立乙個自定義列表 如何建立乙個註腳 注釋也是必不可少的 katex數學公式 新的甘特圖功能,豐富你的文章 uml 圖表 flowchart流程圖 匯出與匯入 你好!這是你第一次使用markdown編輯器所展示的歡迎頁。如果你想學習如何使用markdown編輯器,可以仔細閱讀這篇文章,了解一下mar...

延遲佇列 redis

三 缺點 總結延遲佇列的實現方式有多種,這裡用redis 的zset 來實現 使用 zset 思路 我們給每個value設定score 過期時間的時間戳 例如 當前時間戳是 1609154995707 60秒後過期,則可以設定score 1609154995707 60 然後倒序排列,每次取出一批過...