詳解Java線程池隊(duì)列中的延遲隊(duì)列DelayQueue
在阻塞隊(duì)里中,除了對(duì)元素進(jìn)行增加和刪除外,我們可以把元素的刪除做一個(gè)延遲的處理,即使用DelayQueue的方法。本文就來和大家聊聊Java線程池隊(duì)列中的DelayQueue—延遲隊(duì)列
public enum QueueTypeEnum {
ARRAY_BLOCKING_QUEUE(1, "ArrayBlockingQueue"),
LINKED_BLOCKING_QUEUE(2, "LinkedBlockingQueue"),
DELAY_QUEUE(3, "DelayQueue"),
PRIORITY_BLOCKING_QUEUE(4, "PriorityBlockingQueue"),
SYNCHRONOUS_QUEUE(5, "SynchronousQueue"),
LINKED_TRANSFER_QUEUE(6, "LinkedTransferQueue"),
LINKED_BLOCKING_DEQUE(7, "LinkedBlockingDeque"),
VARIABLE_LINKED_BLOCKING_QUEUE(8, "VariableLinkedBlockingQueue"),
MEMORY_SAFE_LINKED_BLOCKING_QUEUE(9, "MemorySafeLinkedBlockingQueue");
}DelayQueue延遲隊(duì)列
類似于PriorityBlockingQueue,是二叉堆實(shí)現(xiàn)的無界優(yōu)先級(jí)阻塞隊(duì)列。要求元素都實(shí)現(xiàn)Delayed 接口,通過執(zhí)行時(shí)延從隊(duì)列中提取任務(wù),只有在延遲期滿后才能從中提取元素。DelayQueue的泛型參數(shù)需要實(shí)現(xiàn)Delayed接口,Delayed接口繼承了Comparable接口,DelayQueue內(nèi)部使用非線程安全的優(yōu)先隊(duì)列(PriorityQueue),并使用Leader/Followers模式,最小化不必要的等待時(shí)間。DelayQueue不允許包含null元素。
public interface Delayed extends Comparable<Delayed> {
/**
* 返回與此對(duì)象關(guān)聯(lián)的剩余延遲(給定的時(shí)間單位)。
* @param unit 時(shí)間單位
* @返回剩余延遲;零值或負(fù)值表示 延遲已過期
*/
long getDelay(TimeUnit unit);
}DelayQueue使用場(chǎng)景
緩存系統(tǒng)的設(shè)計(jì):可以用DelayQueue保存緩存元素的有效期,使用一個(gè)線程循環(huán)查詢DelayQueue,一旦能從DelayQueue中獲取元素時(shí),表示緩存有效期到了。
定時(shí)任務(wù)調(diào)度:使用DelayQueue保存當(dāng)天將會(huì)執(zhí)行的任務(wù)和執(zhí)行時(shí)間,一旦從DelayQueue中獲取到任務(wù)就開始執(zhí)行,從比如TimerQueue就是使用DelayQueue實(shí)現(xiàn)的。
DelayQueue屬性
//可重入同步鎖 private final transient ReentrantLock lock = new ReentrantLock(); //DelayQueue的實(shí)現(xiàn)依賴于PriorityQueue(優(yōu)先隊(duì)列) private final PriorityQueue<E> q = new PriorityQueue<E>(); //第一個(gè)等待某個(gè)延時(shí)對(duì)象的線程,在延時(shí)對(duì)象還沒有到期時(shí)其他線程看到這個(gè)leader不為null,那么就直接wait //主要是為了避免大量線程在同一時(shí)間點(diǎn)喚醒,導(dǎo)致大量的競(jìng)爭(zhēng),反而影響性能 private Thread leader = null; //條件隊(duì)列,用于wait線程 private final Condition available = lock.newCondition();
DelayQueue構(gòu)造方法
//從上面屬性就可以看出,DelayQueue采用了餓漢模式,調(diào)用構(gòu)造方法即創(chuàng)建了隊(duì)列實(shí)例
public DelayQueue() {}
/**
* 創(chuàng)建一個(gè)DelayQueue,最初包含給定的Collection實(shí)例集合。
* @param c 最初包含的元素集合
*/
public DelayQueue(Collection<? extends E> c) {
this.addAll(c);
}實(shí)現(xiàn)Delayed接口使用示例
class MyDelay<T> implements Delayed {
long delayTime; // 延遲時(shí)間
long expire; // 過期時(shí)間
T data;
public MyDelay(long delayTime, T t) {
this.delayTime = delayTime;
// 過期時(shí)間 = 當(dāng)前時(shí)間 + 延遲時(shí)間
this.expire = System.currentTimeMillis() + delayTime;
data = t;
}
/**
* 剩余時(shí)間 = 到期時(shí)間 - 當(dāng)前時(shí)間
*/
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(this.expire - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
/**
* 優(yōu)先級(jí)規(guī)則:兩個(gè)任務(wù)比較,時(shí)間短的優(yōu)先執(zhí)行
*/
@Override
public int compareTo(Delayed o) {
long f = this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS);
return (int) f;
}
@Override
public String toString() {
return "delayTime=" + delayTime +
", expire=" + expire +
", data=" + data;
}
}
public class DelayQueueDemo {
static BlockingQueue<Delayed> queue = new DelayQueue();
public static void main(String[] args) throws InterruptedException {
queue.add(new MyDelay(8, "第一次添加任務(wù)"));
queue.add(new MyDelay(3, "第二次添加任務(wù)"));
queue.add(new MyDelay(5, "第三次添加任務(wù)"));
while (!queue.isEmpty()) {
Delayed delayed = queue.take();
System.out.println(delayed);
}
}
}DelayQueue總結(jié)
DelayQueue其實(shí)采用了裝飾器模式,在對(duì)PriorityQueue進(jìn)行包裝下增加了延時(shí)時(shí)間獲取元素的功能,其主要特點(diǎn)歸納如下:
- DelayQueue是一個(gè)無界阻塞隊(duì)列,隊(duì)列內(nèi)部使用PriorityQueue來實(shí)現(xiàn)
- 進(jìn)入隊(duì)列的元素必須實(shí)現(xiàn)Delayed接口,在創(chuàng)建元素時(shí)可以指定多久才能從隊(duì)列中獲取當(dāng)前元素,只有在延遲期滿時(shí)才能從中提取元素
- 該隊(duì)列頭部是延遲期滿后保存時(shí)間最長(zhǎng)的Delayed元素
- 如果沒有延遲未過期元素,且隊(duì)列沒有頭部,并且poll將返回null
- 當(dāng)一個(gè)元素的getDelay(TimeUnit.NANOSECONDS)方法返回一個(gè)小于等于0的值時(shí),表示該元素已過期
- 無法使用poll或take移除未到期的元素,也不會(huì)將這些元素作為正常元素對(duì)待;例如:size方法返回到期和未到期元素的計(jì)數(shù)之和
- 此隊(duì)列不允許使用null元素
到此這篇關(guān)于詳解Java線程池隊(duì)列中的延遲隊(duì)列DelayQueue的文章就介紹到這了,更多相關(guān)Java延遲隊(duì)列DelayQueue內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java延遲隊(duì)列DelayQueue原理詳解
- Java中的延遲隊(duì)列DelayQueue詳細(xì)解析
- Java阻塞延遲隊(duì)列DelayQueue原理及使用詳解
- Java中的延遲隊(duì)列DelayQueue源碼解析
- JAVA中的延遲隊(duì)列DelayQueue應(yīng)用解析
- Java的延遲隊(duì)列之DelayQueue解讀
- java并發(fā)中DelayQueue延遲隊(duì)列原理剖析
- Java的DelayQueue延遲隊(duì)列簡(jiǎn)單使用代碼實(shí)例
- Java實(shí)現(xiàn)DelayQueue延遲隊(duì)列示例代碼
相關(guān)文章
Java如何使用httpclient檢測(cè)url狀態(tài)及鏈接是否能打開
這篇文章主要介紹了Java如何使用httpclient檢測(cè)url狀態(tài)及鏈接是否能打開,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
Java使用Apache compress實(shí)現(xiàn)文件夾壓縮成Zip包
Apache common提供了很多實(shí)用的工具包,這篇文章主要來和大家介紹一下Java如何使用Apache compress包實(shí)現(xiàn)文件夾壓縮成Zip包,希望對(duì)大家有所幫助2024-01-01
SpringBoot配置Redis自定義過期時(shí)間操作
這篇文章主要介紹了SpringBoot配置Redis自定義過期時(shí)間操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
IntelliJ?IDEA運(yùn)行SpringBoot項(xiàng)目的詳細(xì)步驟
這篇文章主要介紹了IntelliJ?IDEA如何運(yùn)行SpringBoot項(xiàng)目,步驟一配置maven,步驟二配置JDK環(huán)境,緊接著通過步驟三檢查數(shù)據(jù)庫的配置,最后一步數(shù)據(jù)庫連接,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08
java運(yùn)行錯(cuò)誤A JNI error的解決方案
這篇文章主要介紹了java運(yùn)行錯(cuò)誤A JNI error的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08
Java實(shí)現(xiàn)重定向過程中添加請(qǐng)求頭信息
在Java中,我們經(jīng)常需要使用網(wǎng)絡(luò)請(qǐng)求來與服務(wù)器進(jìn)行通信,在進(jìn)行網(wǎng)絡(luò)請(qǐng)求時(shí),有時(shí)我們需要在重定向過程中添加請(qǐng)求頭信息,本文將介紹如何使用Java在重定向過程中添加請(qǐng)求頭,并提供相應(yīng)的代碼示例,2023-10-10
解析spring-security權(quán)限控制和校驗(yàn)的問題
這篇文章主要介紹了解析spring-security權(quán)限控制和校驗(yàn)的問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03
Spring Data JPA 整合QueryDSL的使用案例
QueryDSL 是一個(gè)用于構(gòu)建類型安全的 SQL 查詢的 Java 庫,它的主要目標(biāo)是簡(jiǎn)化在 Java 中構(gòu)建和執(zhí)行 SQL 查詢的過程,同時(shí)提供類型安全性和更好的編碼體驗(yàn),對(duì)Spring Data JPA 整合QueryDSL使用案例感興趣的朋友跟隨小編一起看看吧2023-08-08

