Java延迟队列DelayQueue的使用:多考生考试模拟

DelayQueue简介

DelayQueue是juc包中的类,它表示的是一个无界的延迟队列,定义如下:

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

DelayQueue存储的元素需要实现Delayed接口以实现优先级比较和延时取得。

DelayQueue还是一个阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部是延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,此时调用 poll() 将直接返回 null,调用 take() 将会发生阻塞,直到有元素发生到期,take() 才会返回。

当一个元素的 getDelay() 方法返回一个小于等于 0 的值时,将发生到期。

场景应用

下面将使用此类实现一个多考生考试的场景:

  1. 考试总时间为10秒,至少2秒后才可进行交卷。
  2. 考生可在2-10秒这段时间内的任意时间交卷。
  3. 考试时间一到,所有未交卷的学生必须交卷。

注:上述时间数据仅为测试方便使用,可根据实际情况进行修改

使用enum定义出时间常量:

    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;
        }
    }

定义学生类

基本定义:

    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获取学生考试花费时间:

    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));
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值