☕【Java 技术指南】教你如何使用【精巧好用】的 DelayQueue(延时队列)
延时队列前提
定时关闭空闲连接:服务器中,有很多客户端的连接,空闲一段时间之后需要关闭之。
定时清除额外缓存:缓存中的对象,超过了空闲时间,需要从缓存中移出。
实现任务超时处理:在网络协议滑动窗口请求应答式交互时,处理超时未响应的请求。
应用在 session 超时管理:网络应答通讯协议的请求超时处理。
痛点方案机制
一种比较暴力的办法就是,使用一个后台线程,遍历所有对象,挨个检查。这种笨笨的办法简单好用,但是对象数量过多时,可能存在性能问题,检查间隔时间不好设置,间隔时间过大,影响精确度,多小则存在效率问题。
而且做不到按超时的时间顺序处理。 这场景,使用 DelayQueue 最适合了。
DelayQueue 是 java.util.concurrent 中提供的一个很有意思的类。很巧妙,非常棒!但是 java doc 和 Java SE 5.0 的 source 中都没有 Sample。我最初在阅读 ScheduledThreadPoolExecutor 源码时,发现 DelayQueue 的妙用。
本文将会对 DelayQueue 做一个介绍,然后列举应用场景。并且提供一个 Delayed 接口的实现和 Sample 代码。
DelayQueue 是一个 BlockingQueue,其特化的参数是 Delayed。
Delayed 扩展了 Comparable 接口,比较的基准为延时的时间值,Delayed 接口的实现类 getDelay 的返回值应为固定值(final)。
DelayQueue 内部是使用 PriorityQueue 实现的。
DelayQueue = BlockingQueue + PriorityQueue + Delayed
DelayQueue 的关键元素 BlockingQueue、PriorityQueue、Delayed。可以这么说,DelayQueue 是一个使用优先队列(PriorityQueue)实现的 BlockingQueue,优先队列的比较基准值是时间。
基本定义如下
DelayQueue 内部的实现使用了一个优先队列。当调用 DelayQueue 的 offer 方法时,把 Delayed 对象加入到优先队列 q 中。如下:
DelayQueue 的 take 方法,把优先队列 q 的 first 拿出来(peek),如果没有达到延时阀值,则进行 await 处理。如下:
以下是 Sample,是一个缓存的简单实现。共包括三个类 Pair、DelayItem、Cache。如下:
以下是 Cache 的实现,包括了 put 和 get 方法,还包括了可执行的 main 函数。
运行 Sample,main 函数执行的结果是输出两行,第一行为 aaa,第二行为 null。
延时队列参数配置热刷新
配置中心勿喷,场景不一样
缓存延时队列的信息都存在配置文件中,比如缓存数量配置、延时超时时间,事件的超时时间等等。当需要该这些配置的值时都需要重新启动进程,改动的配置才会生效,有时候线上的应用不能容忍这种停服。
Apache Common Configuration 给我们提供了可以检测文件修改后配置可短时间生效的功能。具体用法如下:
版权声明: 本文为 InfoQ 作者【李浩宇/Alex】的原创文章。
原文链接:【http://xie.infoq.cn/article/8dae56506b16fea51f929f01f】。文章转载请联系作者。
评论