Java延遲隊列DelayQueue的使用:多考生考試模擬

DelayQueue簡介

DelayQueue是juc包中的類,它表示的是一個無界的延遲隊列,定義以下:java

public class DelayQueue<E extends Delayed> extends AbstractQueue<E> implements BlockingQueue<E>;

DelayQueue存儲的元素須要實現Delayed接口以實現優先級比較和延時取得。dom

DelayQueue仍是一個阻塞隊列,只有在延遲期滿時才能從中提取元素。該隊列的頭部是延遲期滿後保存時間最長的 Delayed 元素。若是延遲都尚未期滿,則隊列沒有頭部,此時調用 poll() 將直接返回 null,調用 take() 將會發生阻塞,直到有元素髮生到期,take() 纔會返回。ide

當一個元素的 getDelay() 方法返回一個小於等於 0 的值時,將發生到期。測試

場景應用

下面將使用此類實現一個多考生考試的場景:this

  1. 考試總時間爲10秒,至少2秒後纔可進行交卷。
  2. 考生可在2-10秒這段時間內的任意時間交卷。
  3. 考試時間一到,全部未交卷的學生必須交卷。

注:上述時間數據僅爲測試方便使用,可根據實際狀況進行修改spa

使用enum定義出時間常量:3d

enum Times {
        SUMMIT_TIME(10), //考試總時間
        SUMBMIT_LIMIT(2), // 交卷限制時間
        MAX_RAND_TIME(15); // 模擬考生所需最大時間
        private final int value;
    
        private Times(int value) {
            this.value = value;
        }
    
        public int getValue() {
            return value;
        }
    }

定義學生類

基本定義:code

class Student implements Delayed {
        private String name;
        private long delay; // 考試花費時間,單位爲毫秒
        private long expire; // 交卷時間,單位爲毫秒
        
        // 此構造可隨機生成考試花費時間
        public Student(String name) { 
            this.name = name;
            this.delay = TimeUnit.MILLISECONDS.convert(getRandomSeconds(), TimeUnit.SECONDS); 
            this.expire = System.currentTimeMillis() + this.delay;
        }
        
        //此構造可指定考試花費時間
        public Student(String name, long delay, TimeUnit unit) {
            this.name = name;
            this.delay = TimeUnit.MILLISECONDS.convert(delay, unit);
            this.expire = System.currentTimeMillis() + this.delay;
        }
        // ...
    }

利用Random獲取學生考試花費時間:orm

public int getRandomSeconds() { // 獲取隨機花費時間,範圍:2-10秒
        return new Random().nextInt(Times.MAX_RAND_TIME.getValue() - Times.SUMBMIT_LIMIT.getValue())
                    + Times.SUMBMIT_LIMIT.getValue();
    }

覆寫的compareTo()和getDelay()方法:對象

其中,getDelay()方法根據傳入的TimeUnit返回剩餘延時。好比,此元素還有2000毫秒延時期滿、傳入的參數爲TimeUnit.SECONDS,那麼返回值爲2,即兩秒。

@Override
    public int compareTo(Delayed o) { // 此方法的實現用於定義優先級
        long td = this.getDelay(TimeUnit.MILLISECONDS);
        long od = o.getDelay(TimeUnit.MILLISECONDS);
        return td > od ? 1 : td == od ? 0 : -1;
    }

    @Override
    public long getDelay(TimeUnit unit) { // 這裏返回的是剩餘延時,當延時爲0時,此元素延時期滿,可從take()取出
        return unit.convert(this.expire - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
    }

主方法實現

  1. 初始化對象

    DelayQueue<Student> queue = new DelayQueue<>();
  2. 添加測試數據

    queue.add(new Student("范冰冰"));
    queue.add(new Student("成  龍"));
    queue.add(new Student("李一桐"));
    queue.add(new Student("宋小寶"));
    queue.add(new Student("吳  京"));
    queue.add(new Student("綠巨人"));
    queue.add(new Student("洪金寶"));
    queue.add(new Student("李雲龍"));
    queue.add(new Student("鋼鐵俠"));
    queue.add(new Student("劉德華"));
    queue.add(new Student("戴安娜"));
  3. 添加一條用於考試結束時強制交卷的屬性

    queue.add(new Student("submit", Times.SUBMIT_TIME.getValue(),TimeUnit.SECONDS));
  4. 開始考試

    while (true) {
        Student s = queue.take(); // 必要時進行阻塞等待
        if (s.getName().equals("submit")) {
            System.out.println("時間已到,所有交卷!");
            // 利用Java8 Stream特性使還沒有交卷學生交卷
            queue.parallelStream()
                 .filter(v -> v.getExpire() >= s.getExpire())
                 .map(Student::submit)
                 .forEach(System.out::println);
            System.exit(0);
        }
        System.out.println(s);
    }

輸出樣例

clipboard.png

完整代碼

package cn.gss.juc;

import java.text.DateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

enum Times {
    SUBMIT_TIME(10), SUMBMIT_LIMIT(2), MAX_RAND_TIME(15);
    private final int value;

    private Times(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}
/**
 * DelayQueue實現多考生考試
 * @author Gss
 */
public class TestDelayedQueue {

    public static void main(String[] args) throws InterruptedException {
        DelayQueue<Student> queue = new DelayQueue<>();
        queue.add(new Student("范冰冰"));
        queue.add(new Student("成  龍"));
        queue.add(new Student("李一桐"));
        queue.add(new Student("宋小寶"));
        queue.add(new Student("吳  京"));
        queue.add(new Student("綠巨人"));
        queue.add(new Student("洪金寶"));
        queue.add(new Student("李雲龍"));
        queue.add(new Student("鋼鐵俠"));
        queue.add(new Student("劉德華"));
        queue.add(new Student("戴安娜"));
        queue.add(new Student("submit", Times.SUBMIT_TIME.getValue(), TimeUnit.SECONDS));
        while (true) {
            Student s = queue.take(); // 必要時進行阻塞等待
            if (s.getName().equals("submit")) {
                System.out.println("時間已到,所有交卷!");
                // 利用Java8 Stream使還沒有交卷學生交卷
                queue.parallelStream()
                     .filter(v -> v.getExpire() >= s.getExpire())
                     .map(Student::submit)
                     .forEach(System.out::println);
                System.exit(0);
            }
            System.out.println(s);
        }
    }

}

class Student implements Delayed {
    private String name;
    private long delay; // 考試花費時間,單位爲毫秒
    private long expire; // 交卷時間,單位爲毫秒

    // 此構造可隨機生成考試花費時間
    public Student(String name) {
        this.name = name;
        this.delay = TimeUnit.MILLISECONDS.convert(getRandomSeconds(), TimeUnit.SECONDS); // 隨機生成考試花費時間
        this.expire = System.currentTimeMillis() + this.delay;
    }

    // 此構造可指定考試花費時間
    public Student(String name, long delay, TimeUnit unit) {
        this.name = name;
        this.delay = TimeUnit.MILLISECONDS.convert(delay, unit);
        this.expire = System.currentTimeMillis() + this.delay;
    }

    public int getRandomSeconds() { // 獲取隨機花費時間
        return new Random().nextInt(Times.MAX_RAND_TIME.getValue() - Times.SUMBMIT_LIMIT.getValue())
                + Times.SUMBMIT_LIMIT.getValue();
    }

    public Student submit() { // 設置花費時間和交卷時間,考試時間結束強制交卷時調用此方法
        setDelay(Times.SUBMIT_TIME.getValue(), TimeUnit.SECONDS);
        setExpire(System.currentTimeMillis());
        return this;
    }

    public String getName() {
        return name;
    }

    public long getExpire() {
        return expire;
    }

    public void setDelay(long delay, TimeUnit unit) {
        this.delay = TimeUnit.MILLISECONDS.convert(delay, TimeUnit.SECONDS);
    }

    public void setExpire(long expire) {
        this.expire = expire;
    }

    @Override
    public int compareTo(Delayed o) { // 此方法的實現用於定義優先級
        long td = this.getDelay(TimeUnit.MILLISECONDS);
        long od = o.getDelay(TimeUnit.MILLISECONDS);
        return td > od ? 1 : td == od ? 0 : -1;
    }

    @Override
    public long getDelay(TimeUnit unit) { // 這裏返回的是剩餘延時,當延時爲0時,此元素延時期滿,可從take()取出
        return unit.convert(this.expire - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
    }

    @Override
    public String toString() {
        return "學生姓名:" + this.name + ",考試用時:" + TimeUnit.SECONDS.convert(delay, TimeUnit.MILLISECONDS) + ",交卷時間:"
                + DateFormat.getDateTimeInstance().format(new Date(this.expire));
    }
}
相關文章
相關標籤/搜索