DelayQueue隊列

DelayQueue是一個支持延時獲取元素的無界阻塞隊列。隊列中的元素必須實現Delayed接口,在建立元素的時候能夠指定多久才能從隊列中獲取當前元素,只有在延遲期滿時才能從隊列中獲取元素。java

咱們能夠將DelayQueue運用在如下應用場景:編程

緩存系統的設計:能夠用DelayQueue保存緩存元素的有效期,使用一個線程循環查詢DelayQueue,一旦能從DelayQueue中獲取元素時,表示緩存有效期到了。緩存

定時任務調度:使用DelayQueue保存當天將會執行的任務和執行時間,一旦從DelayQueue中獲取到任務就開始執行,從好比TimerQueue就是使用DelayQueue實現的。併發

——以上摘自Java併發編程的藝術dom

下面是自已擼的一個小栗子
ide

一、用於執行通知任務的隊列元素
函數

package com.dreyer.concurrent;

import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

/**
 * @description 通知延遲隊列
 * @author: Dreyer
 * @date: 16/4/27 下午2:40
 */
public class NotifyTask implements Runnable, Delayed {
    // 通知名稱
    private String notifyTaskName;
    // 執行時間
    private long executeTime;

    public NotifyTask(String notifyTaskName, long executeTime) {
        this.notifyTaskName = notifyTaskName;
        this.executeTime = executeTime;
    }

    /**
     * 設置延遲時間
     * @param unit
     * @return
     */
    public long getDelay(TimeUnit unit) {
        return unit.convert(executeTime - System.currentTimeMillis(), unit.MILLISECONDS);
    }

    /**
     * 用來指定元素的順序,讓延時時間最長的放在隊列的末尾
     * @param o
     * @return
     */
    public int compareTo(Delayed o) {
        NotifyTask notifyTask = (NotifyTask) o;
        return executeTime > notifyTask.executeTime ? 1 : (executeTime < notifyTask.executeTime ? -1 : 0);
    }

    public void run() {
        System.out.println("當前時間毫秒數:" + System.currentTimeMillis() + "," + this.toString() + "正在執行...");
    }

    @Override
    public String toString() {
        return "NotifyTask{" +
                "notifyTaskName='" + notifyTaskName + '\'' +
                ", executeTime=" + executeTime +
                '}';
    }
}

二、測試類測試

package com.dreyer.concurrent;

import java.util.Random;
import java.util.concurrent.DelayQueue;

/**
 * @description 測試類
 * @author: Dreyer
 * @date: 16/4/27 下午3:56
 */
public class NotifyTaskTest {
    /**
     * 通知任務存放的延遲隊列
     */
    public static DelayQueue<NotifyTask> tasks = new DelayQueue<NotifyTask>();


    public static void main(String[] args) {
        Random random = new Random();
        for (int i = 0; i < 5; i++) {
            // 隨機產生一個秒數
            int seconds = random.nextInt(5) + 1;
            NotifyTask notifyTask = new NotifyTask("任務" + i,System.currentTimeMillis() + (seconds * 1000));
            tasks.put(notifyTask);
        }
        long start = System.currentTimeMillis();
        while (true) {
            NotifyTask notifyTask = tasks.poll();

            if (notifyTask != null) {
                notifyTask.run();
            }
            // 若是隊列中的元素所有被取完,則跳出循環
            if (tasks.size() == 0) {
                break;
            }
            System.out.println("is running......");
        }
        System.out.println("耗時:" + (System.currentTimeMillis() - start) / 1000 + "ms");

    }

}

三、執行結果(部分)this

......spa

is running......

is running......

is running......

is running......

is running......

is running......

is running......

is running......

is running......

is running......

當前時間毫秒數:1461762721192,NotifyTask{notifyTaskName='任務0', executeTime=1461762721192}正在執行...

is running......

當前時間毫秒數:1461762721192,NotifyTask{notifyTaskName='任務1', executeTime=1461762721192}正在執行...

耗時:5ms

從結果中,咱們能夠看出NotifyTask的executeTime是設置在何時執行,那它的執行時間也會是那個時候


注意點:

栗子中的構造函數設置的延遲時間參數executeTime的單位是毫秒,getDelay()方法能夠指定任意單位(栗子中指定的是毫秒),建議不要使用值過大的單位,好比秒 / 分,若是getDelay()方法返回的是一個負數,那隊列中能當即獲取到元素。

關於DelayQueue在公司項目裏面的應用場景主要是:

訂單支付成功或者失敗後要給商戶發送相應的通知,針對同一條通知記錄,若是是第一次發,則須要等待的時間是0分鐘,第二次發則須要等待1分鐘,第三次發則須要等待3分鐘,即發送次數每+1,則須要等待的時長也要相應的增長,那使用DelayQueue就能很好的實現這個功能了。

相關文章
相關標籤/搜索