在阻塞隊裡,除了對元素進行增加和刪除外,我們可以把元素的刪除做一個延遲的處理,也就是使用DelayQueue的方法。本文就來跟大家聊聊Java執行緒池佇列中的DelayQueue—延遲佇列
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"); }
類似PriorityBlockingQueue,是二元堆疊實現的無界優先權阻塞隊列。要求元素都實現Delayed 接口,透過執行時延從佇列中提取任務,只有在延遲期滿後才能從中提取元素。 DelayQueue的泛型參數需要實現Delayed接口,Delayed接口繼承了Comparable接口,DelayQueue內部使用非線程安全的優先隊列(PriorityQueue),並使用Leader/Followers模式,最小化不必要的等待時間。 DelayQueue不允許包含null元素。
public interface Delayed extends Comparable<Delayed> { /** * 返回与此对象关联的剩余延迟(给定的时间单位)。 * @param unit 时间单位 * @返回剩余延迟;零值或负值表示 延迟已过期 */ long getDelay(TimeUnit unit); }
快取系統的設計:可以用DelayQueue儲存快取元素的有效期,使用一個執行緒循環查詢DelayQueue,一旦能從DelayQueue中取得元素時,表示快取有效期限到了。
定時任務排程:使用DelayQueue保存當天將會執行的任務和執行時間,一旦從DelayQueue中獲取到任務就開始執行,從比如TimerQueue就是使用DelayQueue實現的。
//可重入同步锁 private final transient ReentrantLock lock = new ReentrantLock(); //DelayQueue的实现依赖于PriorityQueue(优先队列) private final PriorityQueue<E> q = new PriorityQueue<E>(); //第一个等待某个延时对象的线程,在延时对象还没有到期时其他线程看到这个leader不为null,那么就直接wait //主要是为了避免大量线程在同一时间点唤醒,导致大量的竞争,反而影响性能 private Thread leader = null; //条件队列,用于wait线程 private final Condition available = lock.newCondition();
//从上面属性就可以看出,DelayQueue采用了饿汉模式,调用构造方法即创建了队列实例 public DelayQueue() {} /** * 创建一个DelayQueue,最初包含给定的Collection实例集合。 * @param c 最初包含的元素集合 */ public DelayQueue(Collection<? extends E> c) { this.addAll(c); }
class MyDelay<T> implements Delayed { long delayTime; // 延迟时间 long expire; // 过期时间 T data; public MyDelay(long delayTime, T t) { this.delayTime = delayTime; // 过期时间 = 当前时间 + 延迟时间 this.expire = System.currentTimeMillis() + delayTime; data = t; } /** * 剩余时间 = 到期时间 - 当前时间 */ @Override public long getDelay(TimeUnit unit) { return unit.convert(this.expire - System.currentTimeMillis(), TimeUnit.MILLISECONDS); } /** * 优先级规则:两个任务比较,时间短的优先执行 */ @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, "第一次添加任务")); queue.add(new MyDelay(3, "第二次添加任务")); queue.add(new MyDelay(5, "第三次添加任务")); while (!queue.isEmpty()) { Delayed delayed = queue.take(); System.out.println(delayed); } } }
DelayQueue其實採用了裝飾器模式,在PriorityQueue包裝下增加了延時時間取得元素的功能,其主要特點歸納如下:
以上是Java執行緒池佇列中的延遲佇列DelayQueue怎麼使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!