使用DelayQueue 和 FutureTask 实现java中的缓存
来源:互联网 发布:python数据处理怎么样 编辑:程序博客网 时间:2024/05/22 07:04
使用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() { @Override public 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); //如果缓存中存在此可以,则返回已存在的value f = (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(); } @Override public 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; } @Override public long getDelay(TimeUnit unit) { return unit.convert(removeTime - System.currentTimeMillis(), unit); } public T getT() { return t; } public void setT(T t) { this.t = t; } @Override public int hashCode() { return t.hashCode(); } @Override public 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
阅读全文
0 0
- 使用DelayQueue 和 FutureTask 实现java中的缓存
- Java 中的 Future 和 FutureTask 的使用
- FutureTask 实现缓存
- java中callable和futuretask使用
- java并发:FutureTask 和 CountDowmLatch 的使用
- java中的FutureTask类
- Java中的Runnable、Callable、Future、FutureTask的区别和CompletionService的使用场景
- DelayQueue使用
- java DelayQueue
- Java并发编程:Callable、Future和FutureTask的实现
- java中的多线程包---FutureTask
- 【Java】3.DelayQueue使用与分析
- 基于DelayQueue带有回调的超时缓存实现
- Java 异步线程FutureTask的使用和SwingWorker
- java并发编程实战-CyclicBarrier和FutureTask使用
- Redis和DelayQueue设计具有过期时间的缓存
- Java FutureTask正确使用姿势
- Future和FutureTask的使用
- java代码实现外网IP的获取
- LeetCode 2.Add Two Numbers
- Protobuf详解(.Java文件)
- LightOJ
- 将Android Studio工程内置到源码工程编译并设置成默认Launcher
- 使用DelayQueue 和 FutureTask 实现java中的缓存
- What is an abstract class, and when should it be used?
- Android面试题基础集锦《一》
- 利用java对基本汉字(unicode编码4E00-9FA5)进行笔画排序
- linux注销登录用户
- 面向对象特征-多态
- redis命中率计算
- OpenSSL命令---rsautl
- libsvm处理多分类问题