Java延时队列DelayQueue的使用

本文介绍了如何在Java中利用`Delayed`接口实现任务延时,并通过实例展示了如何创建带不同延时的延时队列,包括不释放线程和释放线程两种场景。同时涵盖了使用`CountDownLatch`协调多个线程和定时调度的技巧。
摘要由CSDN通过智能技术生成

应用场景:比如放入队列后延时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的使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值