Java延时队列DelayQueue的使用

应用场景:比如放入队列后延时1分钟发短信,任务延时1分钟再次执行等

实现Delayed接口

package com.xu.tao.model;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

public class Calculatenumber implements Delayed {
    private final long expire;  //到期时间
    private final int date;  //数据

    public int getDate(){
        return date;
    }

//延时时间,单位为毫秒
    public Calculatenumber(long delay, int date) {
        this.date = date;
        expire = System.currentTimeMillis() + delay;    //到期时间 = 当前时间+延迟时间
    }

    /**
     * 用于延迟队列内部比较排序   当前时间的延迟时间 - 比较对象的延迟时间
     * @param o
     * @return
     */
    @Override
    public int compareTo(Delayed o) {
        return (int) (this.getDelay(TimeUnit.MILLISECONDS) -o.getDelay(TimeUnit.MILLISECONDS));
    }

    /**
     * 需要实现的接口,获得延迟时间   用过期时间-当前时间
     * @param unit
     * @return
     */
    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert(this.expire - System.currentTimeMillis() , TimeUnit.MILLISECONDS);
    }
}

测试一:
使用延时队列创建5个延时任务,每个任务有不同的延时时间。(线程不会释放)

    public static void main(String[] args) throws IOException {
        DelayQueue<Calculatenumber> d = new DelayQueue<Calculatenumber>();
        //开一个线程作为生产者
        new Thread(() -> {
            LocalDateTime localDateTime = LocalDateTime.now();
            DateTimeFormatter f1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            System.out.println(localDateTime.format(f1));
            System.out.println("开始放入1");
            d.put(new Calculatenumber(3000, 1));
            System.out.println("开始放入2");
            d.put(new Calculatenumber(2000, 2));
            System.out.println("开始放入3");
            d.put(new Calculatenumber(1000, 3));
            System.out.println("开始放入4");
            d.put(new Calculatenumber(5000, 4));
            System.out.println("开始放入5");
            d.put(new Calculatenumber(500, 5));
        }).start();

        //开一个线程作为消费者
        new Thread(() -> {
            try {
                while (true) {
                    DateTimeFormatter f1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                    System.out.println("开始消费" + d.take().getDate());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        // 开启一个计时调度,延迟 0毫秒(也就是立即开始执行),每秒输出当前时间
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                LocalDateTime localDateTime = LocalDateTime.now();
                DateTimeFormatter f1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                System.out.println(localDateTime.format(f1));
            }
        }, 0L, 1000L);
    }

输出:

2022-01-05 16:27:04
2022-01-05 16:27:04
开始放入1
开始放入2
开始放入3
开始放入4
开始放入5
开始消费5
2022-01-05 16:27:05
开始消费3
2022-01-05 16:27:06
开始消费2
2022-01-05 16:27:07
开始消费1
2022-01-05 16:27:08
2022-01-05 16:27:09
开始消费4
2022-01-05 16:27:10

测试二:
使用延时队列创建5个延时任务,每个任务有不同的延时时间。5个延时任务执行结束后关闭线程,释放线程资源

 public static void main(String[] args) {
        DelayQueue<Calculatenumber> d = new DelayQueue<Calculatenumber>();
        //使用CountDownLatch来等待所有2个线程执行完,计数器初始化为2
        CountDownLatch countDownLatch = new CountDownLatch(2);

        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2);
        //开一个线程作为生产者,放入5个延时任务
        fixedThreadPool.execute(() -> {
            LocalDateTime localDateTime = LocalDateTime.now();
            DateTimeFormatter f1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            System.out.println(localDateTime.format(f1));
            System.out.println("开始放入1");
            d.put(new Calculatenumber(6000, 1));
            System.out.println("开始放入2");
            d.put(new Calculatenumber(500, 2));
            System.out.println("开始放入3");
            d.put(new Calculatenumber(3000, 3));
            System.out.println("开始放入4");
            d.put(new Calculatenumber(5000, 4));
            System.out.println("开始放入5");
            d.put(new Calculatenumber(4000, 5));
            //当此线程执行完,线程计数器减1
            countDownLatch.countDown();
        });

        //原子类变量,用于记录执行5次延时任务执行完成后消费线程退出
        AtomicInteger num = new AtomicInteger(0);
        //开一个线程作为消费者
        fixedThreadPool.execute(() -> {
            try {
                while (true) {
                    System.out.println("开始消费" + d.take().getDate());
                    num.incrementAndGet();
                    System.out.println("num:" + num.get());
                    if (num.get() == 5) {
                        System.out.println("num是5");
                        countDownLatch.countDown();
                        break;
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 开启一个计时调度,延迟 0毫秒(也就是立即开始执行),每秒输出当前时间
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                LocalDateTime localDateTime = LocalDateTime.now();
                DateTimeFormatter f1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                System.out.println(localDateTime.format(f1));
            }
        }, 0L, 1000L);

        //等到线程计数器变为0,也就是确保30个线程都执行完
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //输出最终的num
        System.out.println("延时任务执行结束:" + num);
        //关闭线程池
        fixedThreadPool.shutdown();
        //检测线程状态
        ThreadPoolExecutor tpe = ((ThreadPoolExecutor) fixedThreadPool);
        int activeCount = tpe.getActiveCount();
        int queueSize = tpe.getQueue().size();
        System.out.println("当前排队线程数:" + queueSize);
        System.out.println("当前活动线程数:" + activeCount);
        long completedTaskCount = tpe.getCompletedTaskCount();
        System.out.println("执行完成线程数:" + completedTaskCount);
        long taskCount = tpe.getTaskCount();
        System.out.println("总线程数:" + taskCount);
    }

参考:
Java延时队列DelayQueue的使用

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的DelayQueue是一个特殊的队列,它只允许在指定的间之后才能从队列中取出元素。可以使用DelayQueue来实现一些迟任务的功能,例如任务调度、缓存过期等。 DelayQueue基于PriorityQueue实现,但是它的元素必须实现Delayed接口,Delayed接口中定义了一个getDelay()方法,返回元素的间。 当从DelayQueue中取出元素,如果该元素的间还没有到达,则该元素会被重新加入队列中,直到间到达。 以下是一个简单的使用DelayQueue的例子: ```java import java.util.concurrent.DelayQueue; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; public class DelayQueueExample { public static void main(String[] args) throws InterruptedException { DelayQueue<DelayedElement> delayQueue = new DelayQueue<DelayedElement>(); delayQueue.add(new DelayedElement("element1", 2000)); delayQueue.add(new DelayedElement("element2", 5000)); delayQueue.add(new DelayedElement("element3", 1000)); while (!delayQueue.isEmpty()) { DelayedElement element = delayQueue.take(); System.out.println("Taking element: " + element); } } static class DelayedElement implements Delayed { private String name; private long delayTime; public DelayedElement(String name, long delayTime) { this.name = name; this.delayTime = System.currentTimeMillis() + delayTime; } @Override public long getDelay(TimeUnit unit) { long diff = delayTime - System.currentTimeMillis(); return unit.convert(diff, TimeUnit.MILLISECONDS); } @Override public int compareTo(Delayed o) { if (this.delayTime < ((DelayedElement) o).delayTime) { return -1; } if (this.delayTime > ((DelayedElement) o).delayTime) { return 1; } return 0; } @Override public String toString() { return "DelayedElement{" + "name='" + name + '\'' + ", delayTime=" + delayTime + '}'; } } } ``` 在上面的例子中,我们创建了一个DelayQueue,并向其中添加了三个DelayedElement元素。每个元素都有一个间,分别为2秒、5秒和1秒。 在主线程中,我们不断地从DelayQueue中取出元素,直到队列为空。当元素的间还没有到达,它会被重新加入队列中,直到间到达。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值