DelayQueue延迟队列-实现缓存
延迟阻塞队列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延迟队列-实现缓存的更多相关文章
- DelayQueue延迟队列原理剖析
DelayQueue延迟队列原理剖析 介绍 DelayQueue队列是一个延迟队列,DelayQueue中存放的元素必须实现Delayed接口的元素,实现接口后相当于是每个元素都有个过期时间,当队列进 ...
- 延迟队列DelayQueue
应用场景:有一批广告需要不定时上下架,有可能上下架的时间间隔很长,就没必要用定时器轮询,用延迟队列进行任务执行. public class Test2 { public static void mai ...
- 延迟队列DelayQueue take() 源码分析
延迟队列DelayQueue take() 源码分析 在工作中使用了延迟队列,对其内部的实现很好奇,于是就研究了一下其运行原理,在这里就介绍一下take()方法的源码 1 take()源码 如下所示 ...
- JUC——延迟队列
所谓的延迟队列最大的特征是它可以自动通过队列进行脱离,例如:现在有一些对象被临时保存着,但是有可能该集合对象是一个公共对象,那么里面的某些数据如果不在使用的时候就希望其可以在指定的时间达到后自动的消失 ...
- java延迟队列
大多数用到定时执行的功能都是用任务调度来做的,单身当碰到类似订餐业务/购物等这种业务就不好处理了,比如购物的订单功能,在你的订单管理中有N个订单,当订单超过十分钟未支付的时候自动释放购物车中的商品,订 ...
- 灵感来袭,基于Redis的分布式延迟队列
延迟队列 延迟队列,也就是一定时间之后将消息体放入队列,然后消费者才能正常消费.比如1分钟之后发送短信,发送邮件,检测数据状态等. Redisson Delayed Queue 如果你项目中使用了re ...
- RabbitMQ使用 prefetch_count优化队列的消费,使用死信队列和延迟队列实现消息的定时重试,golang版本
RabbitMQ 的优化 channel prefetch Count 死信队列 什么是死信队列 使用场景 代码实现 延迟队列 什么是延迟队列 使用场景 实现延迟队列的方式 Queue TTL Mes ...
- 10 DelayQueue 延时队列类——Live555源码阅读(一)基本组件类
这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类. 本文由乌合之众 lym瞎编,欢迎转载 www.cnblogs.com/oloroso/ 本文由乌合 ...
- Java 延迟队列使用
延时队列,第一他是个队列,所以具有对列功能第二就是延时,这就是延时对列,功能也就是将任务放在该延时对列中,只有到了延时时刻才能从该延时对列中获取任务否则获取不到…… 应用场景比较多,比如延时1分钟发短 ...
随机推荐
- Redis_安装配置(2)
一.安装gcc依赖 由于 redis 是用 C 语言开发,安装之前必先确认是否安装 gcc 环境(gcc -v),如果没有安装,执行以下命令进行安装 $ yum install -y gcc 上面命令 ...
- Linux系统使用crt登录之后如何显示横幅消息
打开 /etc/motd 编辑内容即可 效果如下
- VMware桥接模式连接局域网和互联网
第一步:确认本地网关地址 第二步选择桥接模式: 我比较幸运,桥接到"自动",就已经连接成功.不用逐个试错. 修改 ifcfg-ens33 和 新建 ifcfg-br0 [root@ ...
- nuxt 项目安装及环境配置
babel篇 在package.json中添加--exec babel-node 如果需要编译es6,我们需要设置presets包含es2015,也就是预先加载es6编译的模块. 如果需要编译es7, ...
- eclipse中配置Webdriver
安装JDK,配置好Java环境 下载Eclipse,并完成安装 下载Webdriver的JAR文件(访问Selenium官网,下载Java版的zip文件,并且解压到本地磁盘,解压后文件夹内容如下图:) ...
- 《剑指offer》面试题16. 数值的整数次方
问题描述 实现函数double Power(double base, int exponent),求base的exponent次方.不得使用库函数,同时不需要考虑大数问题. 示例 1: 输入: 2.0 ...
- 【小实验】rust的数组是在堆上分配还是在栈上分配的呢?
先看代码: fn main(){ let v = [1,2,3,4,5]; let addr = &v[0] as *const i32 as usize; println!("ar ...
- golang gin框架中实现大文件的流式上传
一般来说,通过c.Request.FormFile()获取文件的时候,所有内容都全部读到了内存.如果是个巨大的文件,则可能内存会爆掉:且,有的时候我们需要一边上传一边处理. 以下的代码实现了大文件流式 ...
- deepin20体验
现在Ubuntu20吊打deepin20 100条街.撑了20天受不了deepin 优点 开机启动设置简单,即使不是应用商店的应用也很好 deepin仓库不用代理也很快.,而且有些Ubuntu下载不了 ...
- ASP.NET 内联代码、内联表达式、数据绑定表达式使用方法罗列(形式就是常说的尖括号 百分号 等于号 井号)
今天在做渭南电脑维修网的一个小功能时遇到了一些问题,因此特别列出,以备他日之用. 首先对ASP.NET 内联代码.内联表达式.数据绑定表达式的概念进行罗列,详细概念以及基本的用法我就不在这里罗嗦了,请 ...