java延遲隊列DelayQueue使用及原理
阿新 • • 發佈:2019-04-10
-s col 註意 ans 等於 xtend time abstract row
概述
java延遲隊列提供了在指定時間才能獲取隊列元素的功能,隊列頭元素是最接近過期的元素。沒有過期元素的話,使用poll()方法會返回null值,超時判定是通過getDelay(TimeUnit.NANOSECONDS)方法的返回值小於等於0來判斷。延時隊列不能存放空元素。
延時隊列實現了Iterator接口,但iterator()遍歷順序不保證是元素的實際存放順序。
隊列元素
DelayQueue<E extends Delayed>的隊列元素需要實現Delayed接口,該接口類定義如下:
public interface Delayed extendsComparable<Delayed> { /** * Returns the remaining delay associated with this object, in the * given time unit. * * @param unit the time unit * @return the remaining delay; zero or negative values indicate * that the delay has already elapsed */ longgetDelay(TimeUnit unit); }
由Delayed定義可以得知,隊列元素需要實現getDelay(TimeUnit unit)方法和compareTo(Delayed o)方法, getDelay定義了剩余到期時間,compareTo方法定義了元素排序規則,註意,元素的排序規則影響了元素的獲取順序,將在後面說明。
內部存儲結構
DelayedQuene的元素存儲交由優先級隊列存放。
public class DelayQueue<E extends Delayed> extends AbstractQueue<E> implementsBlockingQueue<E> { private final transient ReentrantLock lock = new ReentrantLock(); private final PriorityQueue<E> q = new PriorityQueue<E>();//元素存放
DelayedQuene的優先級隊列使用的排序方式是隊列元素的compareTo方法,優先級隊列存放順序是從小到大的,所以隊列元素的compareTo方法影響了隊列的出隊順序。
獲取隊列元素
非阻塞獲取
public E poll() { final ReentrantLock lock = this.lock; lock.lock(); try { E first = q.peek(); if (first == null || first.getDelay(NANOSECONDS) > 0) return null; else return q.poll(); } finally { lock.unlock(); } }
------------------------------------------------------------------------------------------------------------------------
PriorityQueue隊列peek()方法。
public E peek() {
return (size == 0) ? null : (E) queue[0];
}
由代碼我們可以看出,獲取元素時,總是判斷PriorityQueue隊列的隊首元素是否到期,若未到期,返回null,所以compareTo()的方法實現不當的話,會造成隊首元素未到期,當隊列中有到期元素卻獲取不到的情況。因此,隊列元素的compareTo方法實現需要註意。
阻塞方式獲取
public E take() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { for (;;) { E first = q.peek(); if (first == null) //沒有元素,讓出線程,等待java.lang.Thread.State#WAITING available.await(); else { long delay = first.getDelay(NANOSECONDS); if (delay <= 0) // 已到期,元素出隊 return q.poll(); first = null; // don‘t retain ref while waiting if (leader != null) available.await();// 其它線程在leader線程TIMED_WAITING期間,會進入等待狀態
else { Thread thisThread = Thread.currentThread(); leader = thisThread; try { available.awaitNanos(delay);// 等待剩余時間後,再嘗試獲取元素,他在等待期間,由於leader是當前線程,所以其它線程會等待。 } finally { if (leader == thisThread) leader = null; } } } } } finally { if (leader == null && q.peek() != null) available.signal(); lock.unlock(); } }
java延遲隊列DelayQueue使用及原理