【每日面试】Java中的DelayQueue

 看消息中间件的时候,涉及到延时消息的场景,在一篇文章中提到了Java中的DelayQueue也可以实现延时队列的效果,研究一下。

图片

1.

基础信息

1)一个泛型类,最早出现版本在JDK5,属于java.util.concurrent包下,直接继承了AbstractQueue<E>类,直接实现BlockingQueue<E>接口。

2)泛型对象对应的类要实现接口Delayed才可以。

3)一个空参构成,一个有参构造,17个public方法可用,看起来也不是很难懂。

4)因为间接实现了Collection接口,所以它也是集合下的一员,属于Queue这个系列下的实现类,集合的一些方法它也可以用。

5)使用put和offer方法都可以向队列中放入数据,看了下源码,put方法也是调用offer方法,在offer方法中使用了lock锁,所以这里的操作是线程安全的。最终使用的是类PriorityQueue中的offer方法,底层最终使用数组来存放对象。所以可以说这个类的底层数据结构是数组。

图片

2.

看起来不复杂,参考了几篇文章,确实可以在生产者-消费者的场景下去使用。生产者把对象放到队列中,消费者从中取出即可,通过设置过期时间,可以达到延时的效果,但里面好像有很多需要注意的地方,这个在以后使用时再细致看吧。

图片

3.

来看一个简单的使用案例。

1)首先准备放入队列的对象,需要实现接口Delayed,并且重写getDelay和compareTo方法,对于compareTo方法要格外注意,操作不当,可能会造成队列中的对象数据排序错乱,导致延时的效果失效。


package com.itdr.demo;

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

public class A implements Delayed {

    private String name;
    private long avaibleTime;

    public A(String name, long delayTime){
        this.name=name;
        //avaibleTime = 当前时间+ delayTime
        this.avaibleTime=delayTime + System.currentTimeMillis();

    }

    @Override
    public long getDelay(TimeUnit unit) {
        //判断avaibleTime是否大于当前系统时间,并将结果转换成MILLISECONDS
        long diffTime= avaibleTime- System.currentTimeMillis();
        return unit.convert(diffTime,TimeUnit.MILLISECONDS);
    }

    @Override
    public int compareTo(Delayed o) {
        //compareTo用在DelayedUser的排序
        return (int)(this.avaibleTime - ((A) o).getAvaibleTime());
    }
}

2)创建一个生产者,没什么套路,就是用线程定期创建A对象


package com.itdr.demo;

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

public class DelayedQueueProducer implements Runnable {
    // 队列
    private DelayQueue<A> delayQueue;
    // 生产次数
    private Integer messageCount;
    // 过期时间
    private long delayedTime;

    @Override
    public void run() {
        for (int i = 0; i < messageCount; i++) {
            try {
                A a = new A(
                        new Random().nextInt(1000)+"", delayedTime);
                delayQueue.put(a);
                System.out.println("生产一个A");
                Thread.sleep(500);
            } catch (InterruptedException e) {
            }
        }
    }
}

3)创建一个消费者,也是线程,跟生产者交替操作,便于演示

package com.itdr.demo;

import java.util.concurrent.DelayQueue;

public class DelayedQueueConsumer implements Runnable {

    private DelayQueue<A> delayQueue;
    private int messageCount;

    @Override
    public void run() {
        for (int i = 0; i < messageCount; i++) {
            try {
                A element = delayQueue.take();
                System.out.println("消费一个A");
            } catch (InterruptedException e) {
            }
        }
    }
}

4)然后就是调用线程演示就可以了,正常情况下,会生产一个,消费一个这样。

图片

使用确实不难,但看了好几篇文章,都说要格外注意很多细节,在这不一一列出了,本文算是一个普及操作,知道这是个啥东西,大概能干啥,算是对MQ的一个小扩展了解,所以不做深究了。

有什么好想法,可以留言哦~

图片

参考文章:

java中DelayQueue的使用

https://www.cnblogs.com/flydean/p/java-delayqueue.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
JavaDelayQueue是一个基于优先级队列实现的延迟队列。它可以用于定时任务调度、缓存过期等场景。 DelayQueue的元素必须实现Delayed接口,该接口继承自Comparable接口,因此元素需要实现compareTo方法,以便在队列维护元素的优先级。 DelayQueue的元素按照延迟时间的大小进行排序,即延迟时间短的元素排在队列的前面。当从队列取出元素时,只有延迟时间到了的元素才会被取出。 以下是一个使用DelayQueue的简单示例: ```java import java.util.concurrent.DelayQueue; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; public class DelayQueueDemo { public static void main(String[] args) throws InterruptedException { DelayQueue<DelayedElement> queue = new DelayQueue<>(); queue.add(new DelayedElement("task1", 3000)); // 延迟3秒执行 queue.add(new DelayedElement("task2", 2000)); // 延迟2秒执行 queue.add(new DelayedElement("task3", 1000)); // 延迟1秒执行 while (!queue.isEmpty()) { DelayedElement element = queue.take(); // 取出元素 System.out.println(System.currentTimeMillis() + ": " + element); } } } class DelayedElement implements Delayed { private String name; private long expireTime; public DelayedElement(String name, long delay) { this.name = name; this.expireTime = System.currentTimeMillis() + delay; } @Override public long getDelay(TimeUnit unit) { return unit.convert(expireTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS); } @Override public int compareTo(Delayed o) { return Long.compare(this.getDelay(TimeUnit.MILLISECONDS), o.getDelay(TimeUnit.MILLISECONDS)); } @Override public String toString() { return "DelayedElement{" + "name='" + name + '\'' + ", expireTime=" + expireTime + '}'; } } ``` 在上面的示例,我们创建了一个DelayQueue对象,并向其添加了三个DelayedElement元素,分别表示3秒、2秒和1秒后执行的任务。然后在一个循环不断取出元素,直到队列为空。由于每个元素的延迟时间不同,因此取出的顺序也是不同的。 以上就是JavaDelayQueue的简单使用方法。需要注意的是,DelayQueue是线程安全的,可以在多线程环境下使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BCS-点心

传播技术之光。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值