延迟阻塞队列DelayQueue

DelayQueue 是一个支持延时获取元素的阻塞队列,

内部采用优先队列 PriorityQueue 存储元素,

同时元素必须实现 Delayed 接口;在创建元素时可以指定多久才可以从队列中获取当前元素,只有在延迟期满时才能从队列中提取元素。

使用场景

  • 缓存系统:当能够从延迟队列DelayQueue中获取到元素时,说明缓存已经过期
  • 定时任务调度:一分钟后发送短信

基于延迟队列,实现一个缓存系统

延迟队列中添加的元素,实现了Delayed接口

public class CacheItem implements Delayed{
private long expireTime; private long currentTime; private String key; public String getKey() {
return key;
} public CacheItem(String key,long expireTime) {
this.key = key;
this.expireTime = expireTime;
this.currentTime = System.currentTimeMillis();
} /**
* 比较方法,用于排序
* 过期时间长的放队尾,时间短的放队首
*/
@Override
public int compareTo(Delayed o) {
if(this.getDelay(TimeUnit.MICROSECONDS) > o.getDelay(TimeUnit.MICROSECONDS))
return 1;
if(this.getDelay(TimeUnit.MICROSECONDS) > o.getDelay(TimeUnit.MICROSECONDS))
return -1;
return 0;
} /**
* 计算剩余的过期时间
* 大于0说明没有过期
*/
@Override
public long getDelay(TimeUnit unit) { return expireTime - unit.MILLISECONDS.toSeconds(System.currentTimeMillis()-currentTime); } }

缓存实现

public class DelayQueueDemo {
static class Cache implements Runnable{
private Map<String,String> itemMap = new HashMap<>(); private DelayQueue<CacheItem> delayQueue = new DelayQueue<>(); private boolean stop = false; // 初始化后就开始检测
public Cache() {
new Thread(this).start();
} public void add(String key,String value,long expireTime) {
CacheItem item = new CacheItem(key,expireTime);
itemMap.put(key, value);
delayQueue.add(item); } public String get(String key) {
return itemMap.get(key);
} public void shutdown() {
stop = true;
} // 开启多线程,检测缓存是否过期
@Override
public void run() {
while(!stop) {
CacheItem item = delayQueue.poll();
if(item != null) {
// 缓存过期
itemMap.remove(item.getKey());
System.out.println("delete expired key:"+item.getKey());
}
}
System.out.println("Cache stop");
}
} public static void main(String[] args) throws Exception{
Cache cache = new Cache();
cache.add("a", "1", 1);
cache.add("b", "2", 2);
cache.add("c", "3", 2);
cache.add("d", "4", 4);
cache.add("e", "5", 6); while(true) {
String a = cache.get("a");
String b = cache.get("b");
String c = cache.get("c");
String d = cache.get("d");
String e = cache.get("e"); if(a == null && b == null && c == null && d == null && e == null) {
break;
}
} TimeUnit.SECONDS.sleep(1);
cache.shutdown();
} }

延迟队列实现原理部分说明

  • 可重入锁 ReentrantLock
  • 优先队列 PriorityQueue

参考连接

DelayQueue延迟队列-实现缓存的更多相关文章

  1. DelayQueue延迟队列原理剖析

    DelayQueue延迟队列原理剖析 介绍 DelayQueue队列是一个延迟队列,DelayQueue中存放的元素必须实现Delayed接口的元素,实现接口后相当于是每个元素都有个过期时间,当队列进 ...

  2. 延迟队列DelayQueue

    应用场景:有一批广告需要不定时上下架,有可能上下架的时间间隔很长,就没必要用定时器轮询,用延迟队列进行任务执行. public class Test2 { public static void mai ...

  3. 延迟队列DelayQueue take() 源码分析

    延迟队列DelayQueue take() 源码分析 在工作中使用了延迟队列,对其内部的实现很好奇,于是就研究了一下其运行原理,在这里就介绍一下take()方法的源码 1 take()源码 如下所示 ...

  4. JUC——延迟队列

    所谓的延迟队列最大的特征是它可以自动通过队列进行脱离,例如:现在有一些对象被临时保存着,但是有可能该集合对象是一个公共对象,那么里面的某些数据如果不在使用的时候就希望其可以在指定的时间达到后自动的消失 ...

  5. java延迟队列

    大多数用到定时执行的功能都是用任务调度来做的,单身当碰到类似订餐业务/购物等这种业务就不好处理了,比如购物的订单功能,在你的订单管理中有N个订单,当订单超过十分钟未支付的时候自动释放购物车中的商品,订 ...

  6. 灵感来袭,基于Redis的分布式延迟队列

    延迟队列 延迟队列,也就是一定时间之后将消息体放入队列,然后消费者才能正常消费.比如1分钟之后发送短信,发送邮件,检测数据状态等. Redisson Delayed Queue 如果你项目中使用了re ...

  7. RabbitMQ使用 prefetch_count优化队列的消费,使用死信队列和延迟队列实现消息的定时重试,golang版本

    RabbitMQ 的优化 channel prefetch Count 死信队列 什么是死信队列 使用场景 代码实现 延迟队列 什么是延迟队列 使用场景 实现延迟队列的方式 Queue TTL Mes ...

  8. 10 DelayQueue 延时队列类——Live555源码阅读(一)基本组件类

    这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类. 本文由乌合之众 lym瞎编,欢迎转载 www.cnblogs.com/oloroso/ 本文由乌合 ...

  9. Java 延迟队列使用

    延时队列,第一他是个队列,所以具有对列功能第二就是延时,这就是延时对列,功能也就是将任务放在该延时对列中,只有到了延时时刻才能从该延时对列中获取任务否则获取不到…… 应用场景比较多,比如延时1分钟发短 ...

随机推荐

  1. [ vue ] 自定义组件的 v-model 理解

    需求场景描述: 1. 在父组件 myself.vue 里面定义数据 button_val 2. 在父组件 myself.vue.里面定义按钮,它的功能是吧 button_val  的值 -1 ---- ...

  2. vue - 指令创建 vue工程

    1.在需要创建工程的文件夹里打开cmd 执行 vue -V 看看版本号是否正常, 创建工程 vue create [工程名称] 如:vue create mytestvue 然后会弹出选择 按方向键, ...

  3. react中使用antd按需加载(第一部)

    什么是react按需加载?简单来说就是当我们引用antd的时候需要引入全局css样式,这会对性能造成一定的影响,那么使用按需加载以后就不需要引入css全局样式了,直接引入功能模块即可,既然需要设置按需 ...

  4. layui 时间插件,change&&done,按照官网写法无效,解决方式!

    摘抄自 hahei2020:https://blog.csdn.net/hahei2020/article/details/79285370 layui 时间插件, 当选择时间或时间发生改变后,按照官 ...

  5. WAFW00F waf识别工具 源码学习

    我实习工作的第一个任务根据已有的java waf识别工具 实现了一个python的waf识别工具 代码结构非常乱 仅仅达到了能用的水平. 顶头svp推荐这个项目当时我已经写好了开始用了自己的 稍微看了 ...

  6. 《剑指offer》面试题22. 链表中倒数第k个节点

    问题描述 输入一个链表,输出该链表中倒数第k个节点.为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点.例如,一个链表有6个节点,从头节点开始,它们的值依次是1.2.3.4.5. ...

  7. 极简promise雏形

    function Promise(fn) { var value = null, callbacks = []; //callbacks为数组,因为可能同时有很多个回调 this.then = fun ...

  8. Javascript中定时器的使用方法

    Javascript中定时器的使用方法 1.间隔定时器(每隔一段时间执行一次代码) 格式:setInterval(函数,时间) //时间单位是毫秒,每隔设置的时间执行函数里的内容一遍(一直执行) // ...

  9. 第01讲:Flink 的应用场景和架构模型

    你好,欢迎来到第 01 课时,本课时我们主要介绍 Flink 的应用场景和架构模型. 实时计算最好的时代 在过去的十年里,面向数据时代的实时计算技术接踵而至.从我们最初认识的 Storm,再到 Spa ...

  10. Rust 连接 PostgreSQL 数据库

    这次,我们使用 postgres 这个 crate 来连接和操作 PostgreSQL 数据库. 创建好项目后,在 cargo.toml 里添加 postgres 的依赖: 首先,导入相关的类型,并创 ...