JUC阻塞佇列之DelayQueue原始碼分析

2021-09-28 19:41:01 字數 2924 閱讀 6937

delayqueue是乙個支援延時獲取元素的無界阻塞佇列。並且佇列中的元素必須實現delayed介面。在建立元素時可以指定多久才能從佇列中獲取當前元素。只有在延遲期滿時才能從佇列中獲取到元素。delayqueue的應用範圍非常廣闊,如可以用它來儲存快取中元素的有效期,也可用它來實現定時任務。

在分析delayqueue原始碼之前,我們先來看看delayd介面,其原始碼定義如下:

public inte***ce delayed extends comparable < delayed >
我們看到,delayed介面繼承了comparable介面,即實現delayed介面的物件必須實現**getdelay(timeunit unit)方法和compareto(t o)方法。這裡compareto(t o)**方法可以用來實現元素的排序,可以將延時時間長的放到佇列的末尾。

上面分析了delayed介面,接下來我們分析delayqueue的建構函式。delayqueue提供了2種建構函式,乙個是無參建構函式,乙個是給定集合為引數的建構函式。其原始碼如下:

/**

* 構建乙個空的delayqueue

*/public delayqueue() {}

/** * 給定集合c為引數的建構函式

* 將集合c中的元素全部放入到delayqueue中

*/public delayqueue(collection < ? extends e > c)

addall方法是abstractqueue抽象類中的方法,其原始碼如下:

public boolean addall(collection < ? extends e > c)
從上面的原始碼中,我們可以看到,abstractqueue抽象類中addall方法實際是呼叫delayqueue類中的add方法來實現的。

delayqueue提供了4中入列操作,分別是:

public boolean add(e e) 

public boolean offer(e e)

return true;

} finally

}public void put(e e)

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

這裡我們從原始碼中可以看到,**add(e e)**方法、**put(e e)方法和offer(e e,long timeout,timeunit unit)方法都是呼叫offer(e e)方法來實現的,這也是為什麼這幾個方法的解釋都是一樣的原因。其中offer(e e)方法的核心又是呼叫了priorityqueue中的offer(e e)**方法,priorityqueue和priorityblockingqueue都是以二叉堆的無界佇列,只不過priorityqueue不是阻塞的而priorityblockingqueue是阻塞的。

delayqueue提供了3**列操作方法,它們分別是:

下面我們來乙個乙個分析出列操作的原來。

poll():

poll操作的原始碼定義如下:

public e poll()  finally 

}

該方法與priorityqueue的poll方法唯一的區別就是多了**if (first == null || first.getdelay(nanoseconds) > 0)**這個條件判斷,該條件是表示如果佇列中沒有元素或者佇列中的元素未過期,則返回null。

take

take操作原始碼定義如下:

public e take() throws interruptedexception  finally }}

}} finally

}

take操作比poll操作稍微要複雜些,但是邏輯還是相對比較簡單。只是在獲取元素的時候先檢查元素的剩餘延時時間,如果剩餘延時時間<=0,則直接返回佇列頭元素。如果剩餘延時時間》0,則判斷leader是否為null,若果leader不為null,則表示已經有執行緒在等待獲取佇列的頭部元素,因此直接進入等待佇列中等待。若果leader為null,則表示這是第乙個獲取頭部元素的執行緒,把當前執行緒賦值給leader,然後超時等待剩餘延時時間。在take操作中需要注意的一點是fist=null,因為如果first不置為null的話會引起記憶體溢位的異常,這是因為在併發的時候,每個執行緒都會持有乙份first,因此first不會被釋放,若果執行緒數過多,就會導致記憶體溢位的異常。

poll(long timeout, timeunit unit)

超時等待獲取佇列元素的原始碼如下:

public e poll(long timeout, timeunit unit) throws interruptedexception  else  finally }}

}} finally

}

這個出列操作的邏輯和take出列操作的邏輯幾乎一樣,唯一不同的在於take是無時間限制等待,而改操作是超時等待。

delayqueue的入列和出列操作邏輯相對比較簡單,就是在獲取元素的時候,判斷元素是否已經過期,若果過期就可以直接獲取,沒有過期的話poll操作是直接返回null,take操作是進入等待佇列中等待。

JUC 阻塞佇列

什麼是阻塞佇列 阻塞佇列常用於生產者和消費者場景,生產者是向佇列裡新增元素的執行緒,消費者是從佇列裡獲取元素的執行緒。阻塞佇列就是生產者用來存放元素 消費者用來獲取元素的容器 為什麼要使用阻塞佇列 就是適用在不得不阻塞的場景如上面所說生產者 和 消費者場景中 要是佇列中為空 消費者不得不進行阻塞 佇...

juc 阻塞佇列BlockingQueue

阻塞佇列blockingqueue的方法分類 方法型別 丟擲異常 特殊值阻塞 超時插入 add e offer e put e offer e,time,unit 移除remove poll take poll time,unit 檢查element peek 不可用不可用 丟擲異常 當阻塞佇列滿時...

JUC阻塞佇列BlockingQueue

前言 最近面試和手動建立執行緒池時都用到了阻塞佇列,不由得產生好奇,一下原理 參考 目錄 第一章 基礎使用 第二章 實現原理 2.1 arrayblockingqueue 2.2 linkedblockingqueue 第三章 執行緒池中所之用的阻塞佇列 juc中實現乙個阻塞佇列一般都會實現bloc...