使用DelayQueue 和 FutureTask 实现java中的缓存
使用DelayQueue、ConcurrentHashMap、FutureTask实现的缓存工具类。
DelayQueue 简介
DelayQueue是一个支持延时获取元素的无界阻塞队列。DelayQueue内部队列使用PriorityQueue来实现。队列中的元素必须实现Delayed接口,在创建元素时可以指定多久才能从队列中获取当前元素。只有在延迟期满时才能从队列中提取元素。
DelayQueue非常有用,可以将DelayQueue运用在以下应用场景。
- 缓存系统的设计:可以用DelayQueue保存缓存元素的有效期,使用一个线程循环查询
DelayQueue,一旦能从DelayQueue中获取元素时,表示缓存有效期到了。 - 定时任务调度:使用DelayQueue保存当天将会执行的任务和执行时间,一旦从
DelayQueue中获取到任务就开始执行,比如TimerQueue就是使用DelayQueue实现的。
ConcurrentHashMap和FutureTask,详见以下:
- http://www.jianshu.com/p/d10256f0ebea
- FutureTask 源码分析
缓存工具类实现
- 支持缓存多长时间,单位毫秒。
- 支持多线程并发。
比如:有一个比较耗时的操作,此时缓冲中没有此缓存值,一个线程开始计算这个耗时操作,而再次进来线程就不需要再次进行计算,只需要等上一个线程计算完成后(使用FutureTask)返回该值即可。
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;public class CacheBean<V> {// 缓存计算的结果private final static ConcurrentMap<String, Future<Object>> cache = new ConcurrentHashMap<>();// 延迟队列来判断那些缓存过期private final static DelayQueue<DelayedItem<String>> delayQueue = new DelayQueue<>();// 缓存时间private final int ms;static {// 定时清理过期缓存Thread t = new Thread() {@Overridepublic void run() {dameonCheckOverdueKey();}};t.setDaemon(true);t.start();}private final Computable<V> c;/*** @param c Computable*/public CacheBean(Computable<V> c) {this(c, 60 * 1000);}/*** @param c Computable* @param ms 缓存多少毫秒*/public CacheBean(Computable<V> c, int ms) {this.c = c;this.ms = ms;}public V compute(final String key) throws InterruptedException {while (true) {//根据key从缓存中获取值Future<V> f = (Future<V>) cache.get(key);if (f == null) {Callable<V> eval = new Callable<V>() {public V call() {return (V) c.compute(key);}};FutureTask<V> ft = new FutureTask<>(eval);//如果缓存中存在此可以,则返回已存在的valuef = (Future<V>) cache.putIfAbsent(key, (Future<Object>) ft);if (f == null) {//向delayQueue中添加key,并设置该key的存活时间delayQueue.put(new DelayedItem<>(key, ms));f = ft;ft.run();}}try {return f.get();} catch (CancellationException e) {cache.remove(key, f);} catch (ExecutionException e) {e.printStackTrace();}}}/*** 检查过期的key,从cache中删除*/private static void dameonCheckOverdueKey() {DelayedItem<String> delayedItem;while (true) {try {delayedItem = delayQueue.take();if (delayedItem != null) {cache.remove(delayedItem.getT());System.out.println(System.nanoTime() + " remove " + delayedItem.getT() + " from cache");}} catch (InterruptedException e) {e.printStackTrace();}}}}class DelayedItem<T> implements Delayed {private T t;private long liveTime;private long removeTime;public DelayedItem(T t, long liveTime) {this.setT(t);this.liveTime = liveTime;this.removeTime = TimeUnit.MILLISECONDS.convert(liveTime, TimeUnit.MILLISECONDS) + System.currentTimeMillis();}@Overridepublic int compareTo(Delayed o) {if (o == null)return 1;if (o == this)return 0;if (o instanceof DelayedItem) {DelayedItem<T> tmpDelayedItem = (DelayedItem<T>) o;if (liveTime > tmpDelayedItem.liveTime) {return 1;} else if (liveTime == tmpDelayedItem.liveTime) {return 0;} else {return -1;}}long diff = getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS);return diff > 0 ? 1 : diff == 0 ? 0 : -1;}@Overridepublic long getDelay(TimeUnit unit) {return unit.convert(removeTime - System.currentTimeMillis(), unit);}public T getT() {return t;}public void setT(T t) {this.t = t;}@Overridepublic int hashCode() {return t.hashCode();}@Overridepublic boolean equals(Object object) {if (object instanceof DelayedItem) {return object.hashCode() == hashCode() ? true : false;}return false;}}
Computable 接口
public interface Computable<V> {V compute(String k);}
测试类
public class FutureTaskDemo {public static void main(String[] args) throws InterruptedException {// 子线程Thread t = new Thread(() -> {CacheBean<String> cb = new CacheBean<>(k -> {try {System.out.println("模拟计算数据,计算时长2秒。key=" + k);TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}return "你好:" + k;}, 5000);try {while (true) {System.out.println("thead2:" + cb.compute("b"));TimeUnit.SECONDS.sleep(1);}} catch (InterruptedException e) {e.printStackTrace();}});t.start();// 主线程while (true) {CacheBean<String> cb = new CacheBean<>(k -> {try {System.out.println("模拟计算数据,计算时长2秒。key=" + k);TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}return "你好:" + k;}, 5000);System.out.println("thead1:" + cb.compute("b"));TimeUnit.SECONDS.sleep(1);}}
}
执行结果:
两个线程同时访问同一个key的缓存。从执行结果发现,每次缓存失效后,同一个key只执行一次计算,而不是多个线程并发执行同一个计算然后缓存。
本人简书blog地址:http://www.jianshu.com/u/1f0067e24ff8
点击这里快速进入简书
GIT地址:http://git.oschina.net/brucekankan/
点击这里快速进入GIT
使用DelayQueue 和 FutureTask 实现java中的缓存相关推荐
- java中Cache缓存的使用
java中Cache缓存 1.JSR107 缓存的整体架构: 2.SpringBoot的缓存抽象 几个重要概念以及缓存注解 其中想要使用缓存直接,就必须开启**@EnableCaching**注解 开 ...
- java中BufferedInputStream缓存为什么使IO效率高?
背景 最近在看socket编程,这里面需要用到stream进行数据的读取和写入.于是代码中用到了BufferedInputStream提高读的效率.所以就一直在想为什么加上buffer就能提高效率了, ...
- java中一级缓存_JavaWeb_(Hibernate框架)Hibernate中一级缓存
Hibernate中一级缓存 Hibernate 中的缓存分为一级缓存和二级缓存,这两个级别的缓存都位于持久化层,并且存储的都是数据库数据的备份.其中一级缓存是 Hibernate 的内置缓存,在前面 ...
- JAVA中DNS缓存设置
我们上网的原点就是打开浏览器,在上方地址栏输入网址的那一刻,这个回车按了之后,发生了很多事情.首先,计算机只懂0和1,也就是说人类的字母网址计算机是不懂的,它只认识IP地址,如果是IPV4那就是4组8 ...
- 聊一聊JAVA中的缓存规范 —— 虽迟但到的JCache API与天生不俗的Spring Cache
为何需要规范 上一章中构建的最简化版本的缓存框架,虽然可以使用,但是也存在一个问题,就是它对外提供的实现接口都是框架根据自己的需要而自定义的.这样一来,项目集成了此缓存框架,后续如果想要更换缓存框架的 ...
- java中一级缓存二级缓存_[Java] hibernate 一级缓存和二级缓存
缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能.缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事 ...
- Java 中常用缓存Cache机制的实现
/* *所谓缓存,就是将程序或系统经常要调用的对象存在内存中,以便其使用时可以快速调用,不必再去创建新的重复的实例.这样做可以减少系统开销,提高系统效率. *内存缓存,也就是实现一个类中静态Map,对 ...
- java中一级缓存_java – 集群环境中的hibernate一级缓存
您的第一个语句不正确,hibernate中的第一级缓存不在同一JVM的边界内维护.它保持在休眠会话的边界内. Hibernate分别处理会话(会话中的实体,这是第一级缓存),即使在同一个jvm中, ...
- java中DelayQueue的使用
文章目录 简介 DelayQueue DelayQueue的应用 总结 java中DelayQueue的使用 简介 今天给大家介绍一下DelayQueue,DelayQueue是BlockingQue ...
最新文章
- linux nfs共享文件
- HttpWebRequest.GetResponse() raises exception when http status code 400 (bad request) is returned
- 9.切换 iframe
- insert执行时oracle如何处理,ORACLE中Insert时字符处理
- Java竞赛目的_ACM竞赛 Java编程小结
- es6-super关键字
- 【java】java boolean 源码分析
- php 如何根据经纬度计算距离,小程序实例:如何根据经纬度计算两点之间的距离(代码)...
- Session History 属性和方法
- ajax的url怎么将后缀补上_球形门锁怎么拆装?球形门锁安装的方法都包括哪些?
- 2021-06-20 表单详解
- Windows系统口令扫描之——使用Tscrack扫描3389口令
- 《点燃我,温暖你》理工男神李峋同款C语言版本爱心
- STM32F429第二篇之推挽输出与开漏输出
- win10休眠_Win10关机后一动键盘就开机怎么解决
- java steam 使用指南-------groupingBy进阶用法
- 阿里暑期实习生面试经验-数据分析岗位
- JVM-详解G1垃圾收集器
- vb读取文本文件某行的内容
- 传《斗战神》美术创作婉拒暴雪挖角 中国游戏人缺少这份傲骨
热门文章
- 九、Spark模块和安装
- 四十二、深入Java中的文件读取操作
- 梦世界服务器修改指令,我的世界梦世界有哪些指令必须知道 梦世界所有必须知道指令汇总...
- matlab中ismember_MATLAB 代码格式化简易版
- MindSpore感恩节重磅福利,华为Mate 40E送送送!
- 今晚直播 | 旷视研究院王毅:用于条件图像生成的注意力归一化
- AAAI 2020 开源论文 | 可建模语义分层的知识图谱补全方法
- f-GAN简介:GAN模型的生产车间
- 微软论文解读:用于视觉对话的多步双重注意力模型
- 你不是一个人在战斗!有人将吴恩达的视频教程做成了文字版