一篇文章搞懂 DelayQueue

2023-12-08 08:58

本文主要是介绍一篇文章搞懂 DelayQueue,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

本文隶属于专栏《100个问题搞定Java并发》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!

本专栏目录结构和参考文献请见100个问题搞定Java并发

正文

WHAT

DelayQueue 是一个无界阻塞队列( BlockingQueue ),用于放置实现了 Delayed 接口的对象,其中的对象只能在其到期时才能从队列中取走。

关于 BlockingQueue 请参考我的博客——BlockingQueue 源码解析(JDK8)

这种队列是有序的,因此队首对象的延迟到期的时间最长。

如果没有任何延迟到期,那么就不会有队首元素,并且 poll() 将返回 null (正因为这样,你不能将 null 放置到这种队列中)。

实践

下面是一个示例,其中的 Delayed 对象自身就是任务,而 DelayedTaskConsumer 将最“紧急”的任务(到期时间最长的任务)从队列中取出,然后运行它。

注意的是这样的 DelayQueue 就成为了优先级队列的一种变体。

package com.shockang.study.java.concurrent.blocking_queue;import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;class DelayedTask implements Runnable, Delayed {private static int counter = 0;private final int id = counter++;private final int delta;private final long trigger;protected static List<DelayedTask> sequence = new ArrayList<>();DelayedTask(int delayInMilliseconds) {delta = delayInMilliseconds;trigger = System.nanoTime() + NANOSECONDS.convert(delta, MILLISECONDS);sequence.add(this);}@Overridepublic long getDelay(TimeUnit unit) {return unit.convert(trigger - System.nanoTime(), NANOSECONDS);}@Overridepublic int compareTo(Delayed arg) {DelayedTask that = (DelayedTask) arg;if (trigger < that.trigger) return -1;if (trigger > that.trigger) return 1;return 0;}@Overridepublic void run() {System.out.print(this + " ");}@Overridepublic String toString() {return String.format("[%d] Task %d", delta, id);}public String summary() {return String.format("(%d:%d)", id, delta);}public static class EndTask extends DelayedTask {EndTask(int delay) {super(delay);}@Overridepublic void run() {sequence.forEach(dt -> System.out.println(dt.summary()));}}
}public class DelayQueueDemo {public static voidmain(String[] args) throws Exception {DelayQueue<DelayedTask> tasks = Stream.concat(new Random(47).ints(20, 0, 4000).mapToObj(DelayedTask::new),Stream.of(new DelayedTask.EndTask(4000))).collect(Collectors.toCollection(DelayQueue::new));while (tasks.size() > 0)tasks.take().run();}
}
[128] Task 12 [429] Task 6 [551] Task 13 [555] Task 2 [693] Task 3 [809] Task 15 [961] Task 5 [1258] Task 1 [1258] Task 20 [1520] Task 19 [1861] Task 4 [1998] Task 17 [2200] Task 8 [2207] Task 10 [2288] Task 11 [2522] Task 9 [2589] Task 14 [2861] Task 18 [2868] Task 7 [3278] Task 16 (0:4000)
(1:1258)
(2:555)
(3:693)
(4:1861)
(5:961)
(6:429)
(7:2868)
(8:2200)
(9:2522)
(10:2207)
(11:2288)
(12:128)
(13:551)
(14:2589)
(15:809)
(16:3278)
(17:1998)
(18:2861)
(19:1520)
(20:1258)

DelayedTask 包含一个称为 sequence 的 List< DelayedTask>,它保存了任务被创建的顺序,因此我们可以看到排序是按照实际发生的顺序执行的

Delay 接口有一个方法, getDelay(),该方法用来告知延迟到期有多长时间,或者延迟在多长时间之前已经到期了。

这个方法强制我们去使用 Timeunit 类,因为这就是参数类型。

这会产生一个非常方便的类,因为你可以很容易地转换单位而无需作任何声明。

例如, delta 的值是以毫秒为单位存储的,但是 System.nanotime ()产生的时间则是以纳秒为单位的。

你可以转换 delta 的值,方法是声明它的单位以及你希望以什么单位来表示,就像下面这样。

NANOSECONDS.convert(delta, MILLISECONDS);

在 getDelay()中,所希望的单位是作为 unit 参数传递进来的,你使用它将当前时间与触发时间之间的差转换为调用者要求的单位,而无需知道这些单位是什么(这是策略设计模式的一个简单示例,在这种模式中,算法的一部分是作为参数传递进来的)。

为了排序, Delayed 接口还继承了 Comparable 接口,因此必须实现 compareTo(),使其可以产生合理的比较。

从输出中可以看到,任务创建的顺序对执行顺序没有任何影响-相反,任务是按照所期望的延迟顺序所执行的。

这篇关于一篇文章搞懂 DelayQueue的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/469267

相关文章

六个案例搞懂mysql间隙锁

《六个案例搞懂mysql间隙锁》MySQL中的间隙是指索引中两个索引键之间的空间,间隙锁用于防止范围查询期间的幻读,本文主要介绍了六个案例搞懂mysql间隙锁,具有一定的参考价值,感兴趣的可以了解一下... 目录概念解释间隙锁详解间隙锁触发条件间隙锁加锁规则案例演示案例一:唯一索引等值锁定存在的数据案例二:

一文彻底搞懂Java 中的 SPI 是什么

《一文彻底搞懂Java中的SPI是什么》:本文主要介绍Java中的SPI是什么,本篇文章将通过经典题目、实战解析和面试官视角,帮助你从容应对“SPI”相关问题,赢得技术面试的加分项,需要的朋... 目录一、面试主题概述二、高频面试题汇总三、重点题目详解✅ 面试题1:Java 的 SPI 是什么?如何实现一个

一文带你搞懂Redis Stream的6种消息处理模式

《一文带你搞懂RedisStream的6种消息处理模式》Redis5.0版本引入的Stream数据类型,为Redis生态带来了强大而灵活的消息队列功能,本文将为大家详细介绍RedisStream的6... 目录1. 简单消费模式(Simple Consumption)基本概念核心命令实现示例使用场景优缺点2

一文带你搞懂Python中__init__.py到底是什么

《一文带你搞懂Python中__init__.py到底是什么》朋友们,今天我们来聊聊Python里一个低调却至关重要的文件——__init__.py,有些人可能听说过它是“包的标志”,也有人觉得它“没... 目录先搞懂 python 模块(module)Python 包(package)是啥?那么 __in

微信公众号脚本-获取热搜自动新建草稿并发布文章

《微信公众号脚本-获取热搜自动新建草稿并发布文章》本来想写一个自动化发布微信公众号的小绿书的脚本,但是微信公众号官网没有小绿书的接口,那就写一个获取热搜微信普通文章的脚本吧,:本文主要介绍微信公众... 目录介绍思路前期准备环境要求获取接口token获取热搜获取热搜数据下载热搜图片给图片加上标题文字上传图片

一文带你搞懂Nginx中的配置文件

《一文带你搞懂Nginx中的配置文件》Nginx(发音为“engine-x”)是一款高性能的Web服务器、反向代理服务器和负载均衡器,广泛应用于全球各类网站和应用中,下面就跟随小编一起来了解下如何... 目录摘要一、Nginx 配置文件结构概述二、全局配置(Global Configuration)1. w

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

java计算机毕设课设—停车管理信息系统(附源码、文章、相关截图、部署视频)

这是什么系统? 资源获取方式在最下方 java计算机毕设课设—停车管理信息系统(附源码、文章、相关截图、部署视频) 停车管理信息系统是为了提升停车场的运营效率和管理水平而设计的综合性平台。系统涵盖用户信息管理、车位管理、收费管理、违规车辆处理等多个功能模块,旨在实现对停车场资源的高效配置和实时监控。此外,系统还提供了资讯管理和统计查询功能,帮助管理者及时发布信息并进行数据分析,为停车场的科学

CSP-J基础之数学基础 初等数论 一篇搞懂(一)

文章目录 前言声明初等数论是什么初等数论历史1. **古代时期**2. **中世纪时期**3. **文艺复兴与近代**4. **现代时期** 整数的整除性约数什么样的整数除什么样的整数才能得到整数?条件:举例说明:一般化: 判断两个数能否被整除 因数与倍数质数与复合数使用开根号法判定质数哥德巴赫猜想最大公因数与辗转相除法计算最大公因数的常用方法:举几个例子:例子 1: 计算 12 和 18

文章解读与仿真程序复现思路——电力自动化设备EI\CSCD\北大核心《考虑燃料电池和电解槽虚拟惯量支撑的电力系统优化调度方法》

本专栏栏目提供文章与程序复现思路,具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源程序擅长文章解读,论文与完整源程序,等方面的知识,电网论文源程序关注python