Java 延时队列及简单使用方式详解

 更新时间:2023年08月10日 11:42:24   作者:假女吖☌  
这篇文章主要介绍了Java延时队列简单使用方式,通过本文学习知道延时队列是什么可以用来干什么,本文通过实例代码介绍的非常详细,需要的朋友可以参考下

Java 延时队列,简单使用方式

前言:首先我们要知道延时队列是什么?可以用来干什么?

是什么?

看名称 队列 可想而知 先进先出 的一个集合。但我们的延时队列并没有完全的遵循这个理念。

DelayQueue 内部其实是基于我们的 优先队列 来实现的,也就是元素的先后顺序是按元素的 Comparable 接口提供的顺序来 出队 的。

DelayQueue 内部的元素必须是 Delayed 的的实现类 而 Delayed 的父接口是 Comparable<Delayed>

Delayed 接口中需要我们实现一个 long getDelay(TimeUnit unit); 元素的剩余时间 TTL

干什么?

  • 定时任务。
  • 重试(5秒重试)。
  • 延时通知。

都可以基于延时队列来实现。

开发中遇到一个这样的需求。

需要一个集合来维护热点数据,但这个热点数据是有时效性的,我们在去查询的时候先要判断下这个热点数据不存在,或者不在有效期内的。才能走剩下的逻辑。

当然这个需求听起来并不复杂。

我们自己实现的话。

是不是需要一个有顺序的集合?

是不是还每个元素都有一个有效期?

是不是还得保证元素出队的顺序?

如果说还有另外一个地方需要复用,我们是不是还得再写一套这样的逻辑。

所以,我们可以直接使用 DelayQueue 来实现这个需求,他天生就能保证我们的集合是有顺序的,并且保证过期的元素不在集合内。

简单使用

延时对象

@Data
static class SimpleDelayed<T> implements Delayed {
    /**
     * 对象创建时间
     */
    @JsonIgnore
    private final Date createDate;
    /**
     * 延时数(单位毫秒)
     */
    private long delayCount;
    private T data;
    public SimpleDelayed(T data, long delayCount) {
        this.data = data;
        this.delayCount = delayCount;
        this.createDate = new Date();
    }
    @Override
    public long getDelay(TimeUnit unit) {
        long diff = this.createDate.getTime() + this.delayCount - System.currentTimeMillis();
        return unit.convert(diff, TimeUnit.MILLISECONDS);
    }
    @Override
    public int compareTo(Delayed delayed) {
        return Long.compare(this.getDelay(TimeUnit.MILLISECONDS),delayed.getDelay(TimeUnit.MILLISECONDS));
    }
}

注意: compareTo 提供的顺序必须要与 getDelay 否则会出现元素过期了但是在队列中。因为 DelayQueue 内部维护的是一个 优先队列 。所以必须保证这两顺序是一致的。所以这里的 compareTo 直接比较了这两的 剩余过期数 越小的越先出队。反之会出现, 延时时间 已过,但是没有出队。 compareTo 靠前,但是过期数未过的数卡着。

延时队列工具类

@Slf4j
public class SimpleDelayQueueUtils {
   /**
     * 1.定义了一个延时队列 队列中元素是我们的SimpleDelayed
     */
    private final static DelayQueue<SimpleDelayed> SIMPLE_DELAYED_DELAY_QUEUE = new DelayQueue<>();
    static{
      	// 2.声明一个异步线程
        CompletableFuture.runAsync(() -> {
          	// 3.通过自旋去出队已过期的元素
            for (;;) {
                try {
					// 4.take() 对头元素出队。
                    log.info("元素已过期{}",SIMPLE_DELAYED_DELAY_QUEUE.take().getData());
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        // 单个线程的线程池,为了不占用fork-join线程池
        }, Executors.newSingleThreadExecutor());
    }
    public static void add(SimpleDelayed... delayeds) {
        SIMPLE_DELAYED_DELAY_QUEUE.addAll(Arrays.asList(delayeds));
    }
  	// 测试
    public static void main(String[] args) {
        SimpleDelayed<String> nonceDelayed = new SimpleDelayQueueUtils.SimpleDelayed<>("111",5001);
        SimpleDelayed<String> nonceDelayed1 = new SimpleDelayQueueUtils.SimpleDelayed<>("222", 4500);
        SimpleDelayQueueUtils.add(nonceDelayed,nonceDelayed1);
    }
}

输出

23:35:00.693 [pool-1-thread-1] INFO com.mfyuan.chenapioperation.util.SimpleDelayQueueUtils - 元素已过期222
23:35:01.189 [pool-1-thread-1] INFO com.mfyuan.chenapioperation.util.SimpleDelayQueueUtils - 元素已过期111

思考

这里的 data 元素是可以灵活替换的,因为我这里的需求是涉及到队列中的元素是否过期。所以这些就已经足够了。

但是当我们把 data ,替换成 Runable 再把出队的的元素通过线程池的方式去调用则就实现了 定时任务 重试 也可以当做 定时任务 来理解,就把当单做一个任务,如果任务执行失败了或者出现异常了,那么我们重新讲元素放入延时队列中即可。

后话

Redis来实现我这个功能,虽然可以实现但是有些地方实现的逻辑也是不简单。更别说引入 redis 的开发成本,杀🐔不需要🐂刀。

Redis zset 是可以保证集合的元素有顺序的, zset ttl 是指这个 zset 整体的过期时间。(不确定,)

到此这篇关于Java 延时队列,简单使用方式的文章就介绍到这了,更多相关java延时队列内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring事件监听机制之@EventListener实现方式详解

    Spring事件监听机制之@EventListener实现方式详解

    这篇文章主要介绍了Spring事件监听机制之@EventListener实现方式详解,ApplicationContext的refresh方法还是初始化了SimpleApplicationEventMulticaster,发送事件式还是先获取ResolvableType类型,再获取发送监听列表,需要的朋友可以参考下
    2023-12-12
  • 一文带你掌握Java ReentrantLock加解锁原理

    一文带你掌握Java ReentrantLock加解锁原理

    这篇文章将为大家详细介绍一下Java中ReentrantLock 加锁和释放锁的原理,以及和 Synchronized 的对比。文中的示例代码讲解详细,希望对大家有所帮助
    2022-12-12
  • springboot项目打成jar包后无法获取static下的静态资源文件的问题分析

    springboot项目打成jar包后无法获取static下的静态资源文件的问题分析

    这篇文章主要介绍了springboot项目打成jar包后无法获取static下的静态资源文件的问题分析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08
  • Java实现可视化走迷宫小游戏的示例代码

    Java实现可视化走迷宫小游戏的示例代码

    这篇文章主要介绍了Java如何实现可视化走迷宫小游戏。本程序适用于java程序员巩固类与对象、文件读取、事件响应、awt包中各种工具的相关概念以及对逻辑能力的锻炼,需要的可以参考一下
    2022-11-11
  • SpringBoot 快速实现 api 接口加解密功能

    SpringBoot 快速实现 api 接口加解密功能

    在项目中,为了保证数据的安全,我们常常会对传递的数据进行加密,Spring Boot接口加密,可以对返回值、参数值通过注解的方式自动加解密,这篇文章主要介绍了SpringBoot 快速实现 api 接口加解密功能,感兴趣的朋友一起看看吧
    2023-10-10
  • Springboot3整合Mybatis3的完整步骤记录

    Springboot3整合Mybatis3的完整步骤记录

    这篇文章主要给大家介绍了关于Springboot3整合Mybatis3的完整步骤,Spring Boot和MyBatis分别是两个功能强大的框架,它们的协同使用可以极大地简化数据访问层的开发,提高整体的开发效率,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-01-01
  • Java中常用修饰符的使用方法汇总

    Java中常用修饰符的使用方法汇总

    下面小编就为大家带来一篇Java中常用修饰符的使用方法汇总。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • 使用spring mail发送html邮件的示例代码

    使用spring mail发送html邮件的示例代码

    本篇文章主要介绍了使用spring mail发送html邮件的示例代码,这里整理了详细的示例代码,具有一定的参考价值,有兴趣的可以了解一下
    2017-09-09
  • Java中synchronized 的4个优化技巧

    Java中synchronized 的4个优化技巧

    本文主要介绍了Java中synchronized的4个优化技巧,synchronized在JDK 1.5 时性能是比较低的,然而在后续的版本中经过各种优化迭代,它的性能也得到了前所未有的提升,下文更多相关资料需要的小伙伴可以参考一下
    2022-05-05
  • JavaWeb基础教程之Java基础加强版

    JavaWeb基础教程之Java基础加强版

    这篇文章主要介绍了JavaWeb基础教程之Java基础加强版的相关资料,需要的朋友可以参考下
    2016-07-07

最新评论