使用DelayQueue、ConcurrentHashMap、FutureTask实现的缓存工具类。

DelayQueue 简介

DelayQueue是一个支持延时获取元素的无界阻塞队列。DelayQueue内部队列使用PriorityQueue来实现。队列中的元素必须实现Delayed接口,在创建元素时可以指定多久才能从队列中获取当前元素。只有在延迟期满时才能从队列中提取元素。

DelayQueue非常有用,可以将DelayQueue运用在以下应用场景。

  1. 缓存系统的设计:可以用DelayQueue保存缓存元素的有效期,使用一个线程循环查询
    DelayQueue,一旦能从DelayQueue中获取元素时,表示缓存有效期到了。
  2. 定时任务调度:使用DelayQueue保存当天将会执行的任务和执行时间,一旦从
    DelayQueue中获取到任务就开始执行,比如TimerQueue就是使用DelayQueue实现的。

ConcurrentHashMap和FutureTask,详见以下:

  1. http://www.jianshu.com/p/d10256f0ebea
  2. FutureTask 源码分析

缓存工具类实现

  1. 支持缓存多长时间,单位毫秒。
  2. 支持多线程并发。
    比如:有一个比较耗时的操作,此时缓冲中没有此缓存值,一个线程开始计算这个耗时操作,而再次进来线程就不需要再次进行计算,只需要等上一个线程计算完成后(使用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中的缓存相关推荐

  1. java中Cache缓存的使用

    java中Cache缓存 1.JSR107 缓存的整体架构: 2.SpringBoot的缓存抽象 几个重要概念以及缓存注解 其中想要使用缓存直接,就必须开启**@EnableCaching**注解 开 ...

  2. java中BufferedInputStream缓存为什么使IO效率高?

    背景 最近在看socket编程,这里面需要用到stream进行数据的读取和写入.于是代码中用到了BufferedInputStream提高读的效率.所以就一直在想为什么加上buffer就能提高效率了, ...

  3. java中一级缓存_JavaWeb_(Hibernate框架)Hibernate中一级缓存

    Hibernate中一级缓存 Hibernate 中的缓存分为一级缓存和二级缓存,这两个级别的缓存都位于持久化层,并且存储的都是数据库数据的备份.其中一级缓存是 Hibernate 的内置缓存,在前面 ...

  4. JAVA中DNS缓存设置

    我们上网的原点就是打开浏览器,在上方地址栏输入网址的那一刻,这个回车按了之后,发生了很多事情.首先,计算机只懂0和1,也就是说人类的字母网址计算机是不懂的,它只认识IP地址,如果是IPV4那就是4组8 ...

  5. 聊一聊JAVA中的缓存规范 —— 虽迟但到的JCache API与天生不俗的Spring Cache

    为何需要规范 上一章中构建的最简化版本的缓存框架,虽然可以使用,但是也存在一个问题,就是它对外提供的实现接口都是框架根据自己的需要而自定义的.这样一来,项目集成了此缓存框架,后续如果想要更换缓存框架的 ...

  6. java中一级缓存二级缓存_[Java] hibernate 一级缓存和二级缓存

    缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能.缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事 ...

  7. Java 中常用缓存Cache机制的实现

    /* *所谓缓存,就是将程序或系统经常要调用的对象存在内存中,以便其使用时可以快速调用,不必再去创建新的重复的实例.这样做可以减少系统开销,提高系统效率. *内存缓存,也就是实现一个类中静态Map,对 ...

  8. java中一级缓存_java – 集群环境中的hibernate一级缓存

    您的第一个语句不正确,hibernate中的第一级缓存不在同一JVM的边界内维护.它保持在休眠会话的边界​​内. Hibernate分别处理会话(会话中的实体,这是第一级缓存),即使在同一个jvm中, ...

  9. java中DelayQueue的使用

    文章目录 简介 DelayQueue DelayQueue的应用 总结 java中DelayQueue的使用 简介 今天给大家介绍一下DelayQueue,DelayQueue是BlockingQue ...

最新文章

  1. linux nfs共享文件
  2. HttpWebRequest.GetResponse() raises exception when http status code 400 (bad request) is returned
  3. 9.切换 iframe
  4. insert执行时oracle如何处理,ORACLE中Insert时字符处理
  5. Java竞赛目的_ACM竞赛 Java编程小结
  6. es6-super关键字
  7. 【java】java boolean 源码分析
  8. php 如何根据经纬度计算距离,小程序实例:如何根据经纬度计算两点之间的距离(代码)...
  9. Session History 属性和方法
  10. ajax的url怎么将后缀补上_球形门锁怎么拆装?球形门锁安装的方法都包括哪些?
  11. 2021-06-20 表单详解
  12. Windows系统口令扫描之——使用Tscrack扫描3389口令
  13. 《点燃我,温暖你》理工男神李峋同款C语言版本爱心
  14. STM32F429第二篇之推挽输出与开漏输出
  15. win10休眠_Win10关机后一动键盘就开机怎么解决
  16. java steam 使用指南-------groupingBy进阶用法
  17. 阿里暑期实习生面试经验-数据分析岗位
  18. JVM-详解G1垃圾收集器
  19. vb读取文本文件某行的内容
  20. 传《斗战神》美术创作婉拒暴雪挖角 中国游戏人缺少这份傲骨

热门文章

  1. 九、Spark模块和安装
  2. 四十二、深入Java中的文件读取操作
  3. 梦世界服务器修改指令,我的世界梦世界有哪些指令必须知道 梦世界所有必须知道指令汇总...
  4. matlab中ismember_MATLAB 代码格式化简易版
  5. MindSpore感恩节重磅福利,华为Mate 40E送送送!
  6. 今晚直播 | 旷视研究院王毅:用于条件图像生成的注意力归一化
  7. AAAI 2020 开源论文 | 可建模语义分层的知识图谱补全方法
  8. f-GAN简介:GAN模型的生产车间
  9. 微软论文解读:用于视觉对话的多步双重注意力模型
  10. 你不是一个人在战斗!有人将吴恩达的视频教程做成了文字版