java缓存系统
第一版
package cache; import java.util.HashMap; import java.util.Map; public class Cache1 { private Map<String, Object> map=new HashMap<String, Object>(); private static Cache1 cache1=new Cache1(); private Cache1(){ } public static Cache1 getInstanceCache1(){ return cache1; } public void setObject(String key,Object value){ map.put(key, value); } public Object getObject(String key){ Object value=null; value=map.get(key); if (value==null) { value=getFromDB(key); // 从远程数据库获得 map.put(key, value); } return value; } /** *仅仅只是模拟 */ private Object getFromDB(String key) { return null; } }
所谓的缓存,就是把经常用的数据存储到内存中,下次用的时候能很快的拿到。因而,上面的核心代码其实就是getObject。但是,得承认,上面的代码实在是太过简陋了。上面的测试程序很简单我就不写了。
第二版
之前第一版的缓存只是个实例代码,还算不上工具,因为它并没有对某一个"计算"操作做包装。我知道我说的很模糊,咱们看代码。
package cache; public interface GetResutl { public Object get(Object o); } package cache; public class ComputeSum implements GetResutl { @Override public Object get(Object o) { if ( !(o instanceof Integer) ){ throw new IllegalArgumentException (o+"is not Integer"); } int n=(int) o; int result=0; for (int i = 1; i <= n; i++) { result+=i; } return result; } } package cache; public class ComputeMultiply implements GetResutl { @Override public Object get(Object o) { if ( !(o instanceof Integer) ){ throw new IllegalArgumentException (o+"is not Integer"); } int n=(int) o; int result=1; for (int i = 1; i <= n; i++) { result*=i; } return result; } }
第一版的缓存系统,不能缓存某种操作的结果。
看了上面的连加,与连乘。
我们就大概知道新的缓存该是个什么样了。
package cache; import java.util.HashMap; import java.util.Map; public class Cache2 { private Map<String, Object> map=new HashMap<String, Object>(); private GetResutl getResutl=null; public Cache2(GetResutl r){ this.getResutl=r; } public void setObject(String key,Object value){ map.put(key, value); } public Object getObject(String key){ Object value=null; value=map.get(key); if (value==null) { value=getResutl.get(key); map.put(key, value); } return value; } }
另外多嘴一句,Cahe2中有一个接口GetResut,之后再调用GetResult的某一个方法,这种设计似乎叫做策略模式。
第三版
如果ComputeMultiply中的get方法的运行需要花很长时间,同时我们也不着急要它计算的结果,第二版的计算是放在一个线程里的,这样效率不高。
我们试试CallAble。
package cache; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; public class ComputeSum implements GetResutl { @Override public Object get(Object o) { final Long n=Long.valueOf((String) o); Callable<Long> c=new Callable<Long>() { @Override public Long call(){ Long result=0L; for (int i = 1; i <= n; i++) { result+=i; } return result; } }; return new FutureTask<>(c); } }
连乘的写法与之类似,不再赘述。
再看cache的写法。
</pre><pre name="code" class="java">package cache; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; public class Cache3 { private Map<String, FutureTask<Object>> map=new HashMap<String, FutureTask<Object> >(); private GetResutl getResutl=null; public Cache3(GetResutl r){ this.getResutl=r; } @SuppressWarnings("unchecked") public Object getObject(String key){ FutureTask<Object> value=null; FutureTask<Object> ft=map.get(key); if (ft==null) { value= (FutureTask<Object>) getResutl.get(key); map.put(key, value); ft=value; } ft.run(); Object result=null; try { result = ft.get(); } catch (InterruptedException | ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } return result; }
我们看看版本三的测试代码
public static void main(String[] args) { GetResutl getResutl=new ComputeSum(); Cache3 c3=new Cache3(getResutl); long t1=0; long t2=0; t1=System.currentTimeMillis(); System.out.println(c3.getObject(""+1234566)); t2=System.currentTimeMillis(); System.out.println(t2-t1 ); t1=System.currentTimeMillis(); System.out.println(c3.getObject(""+1234566)); t2=System.currentTimeMillis(); System.out.println(t2-t1 ); t1=System.currentTimeMillis(); System.out.println(c3.getObject(""+1234567)); t2=System.currentTimeMillis(); System.out.println(t2-t1 ); t1=System.currentTimeMillis(); System.out.println(c3.getObject(""+1234567)); t2=System.currentTimeMillis(); System.out.println(t2-t1 ); t1=System.currentTimeMillis(); System.out.println(c3.getObject(""+1234567)); t2=System.currentTimeMillis(); System.out.println(t2-t1 ); }
输出:
762077221461
16
762077221461
0
762078456028
15
762078456028
0
762078456028
0
第四版
java并发编程中提到的一个例子。
import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; interface Computable<K,V>{ V compute(final K arg); } /** * 实现简单缓存系统 * @author mzy * * @param <K> key * @param <V> value */ public class FutureCache<K,V> implements Computable<K,V>{ private final ConcurrentHashMap<K, Future<V>> cache = new ConcurrentHashMap<K ,Future<V>>(); private final Computable<K, V> c; public FutureCache(Computable<K, V> c) { this.c = c; } @Override public V compute(final K key) { while(true){ Future<V> future = cache.get(key); if(future == null){ Callable<V> eval = new Callable<V>() { @Override public V call() throws Exception { return c.compute(key); } }; FutureTask<V> ftask = new FutureTask<V>(eval); //使用putIfAbsent原子操作避免有上面if(future == null)引起的相同值的缺陷 future = cache.putIfAbsent(key, ftask); if(future == null) { future = ftask; ftask.run(); } } try { return future.get(); } catch (InterruptedException e) { //出现中断异常应该从 cache中移除Future,防止缓存污染 cache.remove(key,future); } catch (ExecutionException e) { //执行中的异常应当抛出,获得恰当处理 throw new RuntimeException(e.getCause()); } } } } 测试程序: public class Test { public static void main(String[] args) { final Computable<Integer, Integer> c = new Computable<Integer, Integer>() { @Override public Integer compute(Integer arg) { Integer sum = 0; for(Integer i=0;i<arg;i++){ sum+=i; } return sum; } }; final Computable<Integer, Integer> cache = new FutureCache<Integer,Integer>(c); long start = System.currentTimeMillis(); cache.compute(10000); long stop = System.currentTimeMillis(); System.out.println(stop-start); start = System.currentTimeMillis(); cache.compute(10000); stop = System.currentTimeMillis(); System.out.println(stop-start); start = System.currentTimeMillis(); cache.compute(10000); stop = System.currentTimeMillis(); System.out.println(stop-start); start = System.currentTimeMillis(); cache.compute(10000); stop = System.currentTimeMillis(); System.out.println(stop-start); } }
参考资料
http://my.oschina.net/ccdvote/blog/131876?p=1
java缓存系统的更多相关文章
- Java核心知识点学习----线程中如何创建锁和使用锁 Lock,设计一个缓存系统
理论知识很枯燥,但这些都是基本功,学完可能会忘,但等用的时候,会发觉之前的学习是非常有意义的,学习线程就是这样子的. 1.如何创建锁? Lock lock = new ReentrantLock(); ...
- 缓存系统MemCached的Java客户端优化历程
Memcached 是什么? Memcached是一种集中式Cache,支持分布式横向扩展.这里需要解释说明一下,很多开发者觉得Memcached是一种分布式缓存系统,但是其实Memcached服务端 ...
- Java核心知识点 --- 线程中如何创建锁和使用锁 Lock , 设计一个缓存系统
理论知识很枯燥,但这些都是基本功,学完可能会忘,但等用的时候,会发觉之前的学习是非常有意义的,学习线程就是这样子的. 1.如何创建锁? Lock lock = new ReentrantLock(); ...
- JAVA 并发编程-读写锁之模拟缓存系统(十一)
在多线程中,为了提高效率有些共享资源同意同一时候进行多个读的操作,但仅仅同意一个写的操作,比方一个文件,仅仅要其内容不变能够让多个线程同一时候读,不必做排他的锁定,排他的锁定仅仅有在写的时候须要,以保 ...
- [Java 缓存] Java Cache之 DCache的简单应用.
前言 上次总结了下本地缓存Guava Cache的简单应用, 这次来继续说下项目中使用的DCache的简单使用. 这里分为几部分进行总结, 1)DCache介绍; 2)DCache配置及使用; 3)使 ...
- Memcache缓存系统构建一
在如今这个高效率的社会中,怎样将这个高效率应用到自己的程序中,是一个值得追寻和值得探讨的问题.因为这个memcache能够很好的提高检索速度,提升用户体验,而且重要的是减少数据库的访问.这就大大的提高 ...
- 深入探讨在集群环境中使用 EhCache 缓存系统
EhCache 缓存系统简介 EhCache 是一个纯 Java 的进程内缓存框架,具有快速.精干等特点,是 Hibernate 中默认的 CacheProvider. 下图是 EhCache 在应用 ...
- (转)java缓存技术,记录
http://blog.csdn.net/madun/article/details/8569860 最近再ITEYE上看到关于讨论JAVA缓存技术的帖子比较多,自己不懂,所以上网大概搜了下,找到一篇 ...
- JAVA缓存技术
介绍 JNotify:http://jnotify.sourceforge.net/,通过JNI技术,让Java代码可以实时的监控制定文件夹内文件的变动信息,支持Linux/Windows/MacOS ...
随机推荐
- Rails多路径调用相同方法原路返回的方法
有时候可能有多条path到达同一个method,此时,我们希望在该方法完成后自动转到之前进入的path中去,其实实现起来非常简单,只需要实现如下两个方法: def redirect_back_or(d ...
- 制定一个apk路径 然后跳出安装界面
制定一个apk的路径 然后跳出界面让用户选择是否安装 我们系统有一个写好的Activity来协助我们完成这一功能 我们来看看它的清单文件 <?xml version="1.0" ...
- 负载均衡LVS(DR模式)安装实战
1.编译安装ipvsadm 首先从LVS官网下载tarball,解压后make && make install即可. 要注意的是LVS的依赖有:popt-static.libnl.ke ...
- 在8X8的棋盘上分布着n个骑士,他们想约在某一个格中聚会。骑士每天可以像国际象棋中的马那样移动一次,可以从中间像8个方向移动(当然不能走出棋盘),请计算n个骑士的最早聚会地点和要走多少天。要求尽早聚会
在8X8的棋盘上分布着n个骑士,他们想约在某一个格中聚会.骑士每天可以像国际象棋中的马那样移动一次,可以从中间像8个方向移动(当然不能走出棋盘),请计算n个骑士的最早聚会地点和要走多少天.要求尽早聚会 ...
- “出错了”和报告Bug的艺术
"出错了." 没有那句话能像"出错了"一样让程序员/开发者如此沮丧,心里翻江倒海,怒火一点即燃,还要死掉一大片脑细胞. 这句生硬的开场白通常标志着让开发者恐惧的 ...
- 如何构建Android MVVM 应用框架
概述 说到Android MVVM,相信大家都会想到Google 2015年推出的DataBinding框架.然而两者的概念是不一样的,不能混为一谈.MVVM是一种架构模式,而DataBinding是 ...
- API创建员工地址
DECLARE ln_address_id PER_ADDRESSES.ADDRESS_ID%TYPE; ln_object_version_number PER_ADDRESSES.OBJECT_V ...
- mac os X下的updatedb
unix或linux下使用locate指令在其数据库中查询文件,使用updatedb可以 更新locate的数据库.而在mac os X下却找不到updated这个程序.使用 man locate查看 ...
- Struts2处理流程性需求的一种解决方案
在应用程序设计中,经常出现如下的需求. 查看用户填写的数据,而且数据是分页填写. 看下面这个情况 用户的信息有三页,分别是Form abc. 现在的问题是,后面的逻辑该如何设计. 如果把,FormAB ...
- 最简单的基于Flash的流媒体示例:RTMP推送和接收(ActionScript)
===================================================== Flash流媒体文章列表: 最简单的基于Flash的流媒体示例:RTMP推送和接收(Acti ...