第一版

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缓存系统的更多相关文章

  1. Java核心知识点学习----线程中如何创建锁和使用锁 Lock,设计一个缓存系统

    理论知识很枯燥,但这些都是基本功,学完可能会忘,但等用的时候,会发觉之前的学习是非常有意义的,学习线程就是这样子的. 1.如何创建锁? Lock lock = new ReentrantLock(); ...

  2. 缓存系统MemCached的Java客户端优化历程

    Memcached 是什么? Memcached是一种集中式Cache,支持分布式横向扩展.这里需要解释说明一下,很多开发者觉得Memcached是一种分布式缓存系统,但是其实Memcached服务端 ...

  3. Java核心知识点 --- 线程中如何创建锁和使用锁 Lock , 设计一个缓存系统

    理论知识很枯燥,但这些都是基本功,学完可能会忘,但等用的时候,会发觉之前的学习是非常有意义的,学习线程就是这样子的. 1.如何创建锁? Lock lock = new ReentrantLock(); ...

  4. JAVA 并发编程-读写锁之模拟缓存系统(十一)

    在多线程中,为了提高效率有些共享资源同意同一时候进行多个读的操作,但仅仅同意一个写的操作,比方一个文件,仅仅要其内容不变能够让多个线程同一时候读,不必做排他的锁定,排他的锁定仅仅有在写的时候须要,以保 ...

  5. [Java 缓存] Java Cache之 DCache的简单应用.

    前言 上次总结了下本地缓存Guava Cache的简单应用, 这次来继续说下项目中使用的DCache的简单使用. 这里分为几部分进行总结, 1)DCache介绍; 2)DCache配置及使用; 3)使 ...

  6. Memcache缓存系统构建一

    在如今这个高效率的社会中,怎样将这个高效率应用到自己的程序中,是一个值得追寻和值得探讨的问题.因为这个memcache能够很好的提高检索速度,提升用户体验,而且重要的是减少数据库的访问.这就大大的提高 ...

  7. 深入探讨在集群环境中使用 EhCache 缓存系统

    EhCache 缓存系统简介 EhCache 是一个纯 Java 的进程内缓存框架,具有快速.精干等特点,是 Hibernate 中默认的 CacheProvider. 下图是 EhCache 在应用 ...

  8. (转)java缓存技术,记录

    http://blog.csdn.net/madun/article/details/8569860 最近再ITEYE上看到关于讨论JAVA缓存技术的帖子比较多,自己不懂,所以上网大概搜了下,找到一篇 ...

  9. JAVA缓存技术

    介绍 JNotify:http://jnotify.sourceforge.net/,通过JNI技术,让Java代码可以实时的监控制定文件夹内文件的变动信息,支持Linux/Windows/MacOS ...

随机推荐

  1. cassandra 3.x官方文档(5)---探测器

    写在前面 cassandra3.x官方文档的非官方翻译.翻译内容水平全依赖本人英文水平和对cassandra的理解.所以强烈建议阅读英文版cassandra 3.x 官方文档.此文档一半是翻译,一半是 ...

  2. Goaccess解析nginx日志备忘

    参考 http://nginx.org/en/docs/http/ngx_http_log_module.html?&_ga=1.92028562.949762386.1481787781#l ...

  3. Android TV开发总结(一)构建一个TV app前要知道的事儿

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52792562 前言:近年来,智能 ...

  4. springMVC源码分析--ControllerClassNameHandlerMapping(九)

    在上一篇博客springMVC源码分析--AbstractControllerUrlHandlerMapping(六)中我们介绍到AbstractControllerUrlHandlerMapping ...

  5. 打开CMDLINE中的 ” earlyprink “ 参数

    点击打开链接 解决问题的过程中,好文章推荐,都保存在火狐wilson_sq@qq.com记录中~~~~~~~~grep -r "earlyprintk" kernelkernel/ ...

  6. Web自动化框架LazyUI使用手册(4)--控件抓取工具Elements Extractor详解(批量抓取)

    概述 前面的一篇博文详细介绍了单个控件抓取的设计思路&逻辑以及使用方法,本文将详述批量控件抓取功能. 批量抓取:打开一个web页面,遍历页面上所有能被抓取的元素,获得每个元素的iframe.和 ...

  7. WmS简介(三)之Activity窗口是如何创建的?基于Android7.0源码

    OK,在前面两篇博客中我们分别介绍了WmS中的token,同时也向小伙伴们区分了Window和窗口的区别,并且按照type值的不同将Android系统中的窗口分为了三大类,那么本篇博客我们就来看看应用 ...

  8. 28 自定义View画坐标和柱状图

    自定义View类 RectView.java package com.qf.sxy.day29_customview.widget; import android.content.Context; i ...

  9. html5全解析

    htm是软件开发中非常基础的知识,也是很重要的知识,在web中是很重要的知识点,在此梳理一下主要内容: 1.HTML是什么? 全称为HyperText Markup Language,超文本标记语言, ...

  10. Hexo写博客

    hexo配置github Git Install hexo-deployer-git. $ npm install hexo-deployer-git –save 配置_config.yml文件 de ...