首頁  >  文章  >  Java  >  Java執行緒池佇列中的延遲佇列DelayQueue怎麼使用

Java執行緒池佇列中的延遲佇列DelayQueue怎麼使用

WBOY
WBOY轉載
2023-04-14 21:22:011128瀏覽

在阻塞隊裡,除了對元素進行增加和刪除外,我們可以把元素的刪除做一個延遲的處理,也就是使用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");
}

DelayQueue延遲佇列

類似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保存當天將會執行的任務和執行時間,一旦從DelayQueue中獲取到任務就開始執行,從比如TimerQueue就是使用DelayQueue實現的。

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建構方法

//从上面属性就可以看出,DelayQueue采用了饿汉模式,调用构造方法即创建了队列实例
public DelayQueue() {}

/**
 * 创建一个DelayQueue,最初包含给定的Collection实例集合。
 * @param c 最初包含的元素集合
 */
public DelayQueue(Collection<? extends E> c) {
    this.addAll(c);
}

實作Delayed介面使用範例

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總結

DelayQueue其實採用了裝飾器模式,在PriorityQueue包裝下增加了延時時間取得元素的功能,其主要特點歸納如下:

  • ##DelayQueue是一個無界阻塞佇列,佇列內部使用PriorityQueue來實作

  • 進入佇列的元素必須實作Delayed接口,在建立元素時可以指定多久才能從佇列中取得目前元素,只有在延遲期滿時才能從中提取元素

  • 該佇列頭部是延遲期滿後保存時間最長的Delayed元素

  • ##如果沒有延遲未過期元素,且佇列沒有頭部,且poll將傳回null
  • 當一個元素的getDelay(TimeUnit.NANOSECONDS)方法傳回小於等於0的值時,表示該元素已過期
  • 無法使用poll或take移除未到期的元素,也不會將這些元素視為正常元素;例如:size方法傳回到期和未到期元素的計數總和
  • 此佇列不允許使用null元素

以上是Java執行緒池佇列中的延遲佇列DelayQueue怎麼使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除