DelayQueue是一個無界阻塞隊列,隊列中的元素比較特殊,必須是實現了Delayed接口的元素。Delayed接口是一個混合接口,它繼承了Comparator接口。它也具有PriorityBlockingQueue的特征,元素中優化級最高的元素是延遲時間最長的元素。隊列頭的元素是呆在隊列時間最長的元素,它只有到時期,才能出隊。即getDelay獲取到的時間小于等于0時,否則返回null元素。
DelayQueue的并發控制同樣使用ReentrantLock和它的Condition對象來實現。因為添加元素不阻塞,所以也只有一個Condition對象來實現等待/通知模式。DelayQueue同樣不允許使用null元素。
一、DelayQueue的結構
DelayQueue的結構和PriorityBlockingQueue基本一致,它持有一個PriorityQueue的引用
各種方法實現也委托給了PriorityQueue對象來實現。另外還有一個ReentrantLock和它的Condition對象;隊列中的元素是Delayed接口類型的元素。
Delayed接口定義:
1 |
public interface Delayed extends Comparable<Delayed> { |
DelayQueue的主要成員變量:
1 |
private transient final ReentrantLock lock = new ReentrantLock(); |
二、DelayQueue的主要方法實現
1、入隊操作
入隊操作因為是無界隊列,所有不會出現阻塞,put/offer都正常添加到隊列中。
1 |
public boolean offer(E e) { |
2、出隊操作
因為出隊必須是到期的元素,如果獲取不到元素,阻塞版本的take會阻塞等待到delay的時間到期,而超時版本的poll會返回null。具體的實現都大同小異,只看take方法的實現:
1 |
public E take() throws InterruptedException { |
具體的實現流程如下:
1).獲取鎖,并加鎖;
2).開始自旋,利用peek方法獲取隊列的頭元素,如果獲取失敗,則釋放鎖,進入Condition的等待隊列;
3).如果能獲取到隊列頭的元素,則判斷到期時間;如果還未到期,則繼續在剩下的時間中await;
4).如果元素已經到時,則獲取成功,poll出隊,同時判斷隊列如果非空,則繼續通知阻塞的線程;
5).最后返回獲取到的元素;
三、使用DelayQueue
DelayQueue可以用于很多場景,比如緩存過期管理、會話過期管理、連接超時管理等。下面的例子是使用DelayQueue來管理緩存中過期的元素。
1、保存數據的鍵值對類:
1 |
public class Pair<K, V> { |
2、實現Delayed接口:
1 |
public class DelayItem<T> implements Delayed { |
3、緩存實現和測試
1 |
public class Cache<K,V> { |