zoukankan      html  css  js  c++  java
  • java动态缓存成长小纪(一)——创建一个简单的缓存

            在实际项目中,我们常常会须要使用到缓存。一般来说,缓存介质是内存;而常见的DB将数据存储在硬盘中的;缓存读取是电脉冲。而硬盘读取是机械地读取转动的硬盘。速度差异是上百倍的。

    所以往往能够通过缓存,对常常常使用到的数据进行訪问。以提快速度。

            创建缓存实际上就是针对两个对象。1. Cache对象,即一个缓存对象;2. CacheManager对象。即一个管理不同缓存的对象,其核心实际上就是一个Map,用来保存与获取不同缓存。

          最简单的缓存 实现例如以下:

    /**
     *  项目名称:
     *  文件说明:创建一个缓存管理器 <span style="font-family: Arial, Helvetica, sans-serif;">刘晨曦</span>
     *  主要特点:
     *  版本:1.0
     *  创建时间:2013-12-3
     **/
    package NBOffer;
    
    import java.util.HashMap;
    
    public class CacheManager {
    
    	static HashMap<String,Cache> cacheMap=new HashMap<String,Cache>();
    	
    	public static Cache getCache(String id)
    	{
    		return cacheMap.get(id);
    	}
    	
    	public static void putCache(Cache cache)
    	{
    		cacheMap.put(cache.id, cache);
    	}
    	
    	public static void main(String[] args) {
    		Cache cache1=new Cache("1","A1");
    		Cache cache2=new Cache("2","A2");
    		CacheManager.putCache(cache1);
    		CacheManager.putCache(cache2);
    		CacheManager.getCache("1").showInfo();
    	}
    }
    
    class Cache
    {
    	String id;//相当于主键
    	Object val;
    	public Cache(String id)
    	{
    		new Cache(id,null);
    	}
    	
    	public Cache(String id,Object val)
    	{
    		this.id=id;
    		this.val=val;
    	}
    	
    	public void setValue(Object val)
    	{
    		this.val=val;
    	}
    	
    	public void showInfo()
    	{
    		System.out.println("Cache的ID是:   "+id+"   Cache的值是:   "+val);
    	}
    }
    


    问题1: 哪一步可以体现出缓存相对于直接读取库的长处?

    实际上是getCache()方法。是从HashMap中读取,也就是从JVM中读取。处于内存中。


    问题2: 缓存若未能命中,岂不是返回空的Cache了?

    是的。所以我们须要对getCache进行改进,未能命中说明缓存里面没有,须要从数据库里面取数。


    /**
     *  项目名称:
     *  文件说明:创建一个缓存管理器 <span style="font-family: Arial, Helvetica, sans-serif;">刘晨曦</span>
     *  主要特点:
     *  版本:1.0
     *  创建时间:2013-12-3
     **/
    package NBOffer;
    
    import java.util.HashMap;
    
    public class CacheManager {
    
    	static HashMap<String,Cache> cacheMap=new HashMap<String,Cache>();
    	
    	public static Cache getCache(String id)
    	{
    		if(cacheMap.get(id)==null)
    		{
    			Object val=getFromDB(id);
    			cacheMap.put(id, new Cache(id,val));
    		}
    		return cacheMap.get(id);
    	}
    	
    	public static void putCache(Cache cache)
    	{
    		cacheMap.put(cache.id, cache);
    	}
    	
    	public static Object getFromDB(String id)
    	{
    	System.out.println("缓慢地从内存中读取id="+id+"相应的数据。。。");	
    	return new String("value"+id);
    	}
    	
    	public static void main(String[] args) {
    		Cache cache1=new Cache("1","value1");
    		Cache cache2=new Cache("2","value2");
    		CacheManager.putCache(cache1);
    		CacheManager.putCache(cache2);
    		CacheManager.getCache("3").showInfo();
    	}
    }
    
    class Cache
    {
    	String id;//相当于主键
    	Object val;
    	public Cache(String id)
    	{
    		new Cache(id,null);
    	}
    	
    	public Cache(String id,Object val)
    	{
    		this.id=id;
    		this.val=val;
    	}
    	
    	public void setValue(Object val)
    	{
    		this.val=val;
    	}
    	
    	public void showInfo()
    	{
    		System.out.println("Cache的ID是:   "+id+"   Cache的值是:   "+val);
    	}
    }
    


    问题3:假设我想定时一段时间刷新缓存。比方,每隔15min刷新一次全部缓存,那我应该怎么办?

    为了方便观察,我们设置为每间隔1s刷新一次。

    /**
     *  项目名称:
     *  文件说明:创建一个缓存管理器 刘晨曦
     *  主要特点:
     *  版本:1.0
     *  创建时间:2013-12-3
     **/
    package NBOffer;
    
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Set;
    
    public class CacheManager {
    
    	static HashMap<String,Cache> cacheMap=new HashMap<String,Cache>();
    	
    	public static Cache getCache(String id)
    	{
    		if(cacheMap.get(id)==null)
    		{
    			Object val=getFromDB(id);
    			cacheMap.put(id, new Cache(id,val));
    		}
    		return cacheMap.get(id);
    	}
    	
    	public static void putCache(Cache cache)
    	{
    		cacheMap.put(cache.id, cache);
    	}
    	
    	public static Object getFromDB(String id)
    	{
    	System.out.println("缓慢地从内存中读取id="+id+"相应的数据。

    。。"); return new String("value"+id); } public static void refreshCaches() { System.out.println("刷新缓存。。

    。"); Set<String> keySet=cacheMap.keySet(); Iterator it=keySet.iterator(); while(it.hasNext()) { String id=(String) it.next(); Object val=getFromDB(id); cacheMap.put(id, new Cache(id,val)); } } public static void main(String[] args) { Cache cache1=new Cache("1","value1"); Cache cache2=new Cache("2","value2"); CacheManager.putCache(cache1); CacheManager.putCache(cache2); CacheManager.getCache("3").showInfo(); Thread refreshTD=new Thread() { public void run() { while(true) { refreshCaches(); try { Thread.sleep(1000);//每一秒刷新一次 } catch (InterruptedException e) { e.printStackTrace(); } } } }; refreshTD.start(); } } class Cache { String id;//相当于主键 Object val; public Cache(String id) { new Cache(id,null); } public Cache(String id,Object val) { this.id=id; this.val=val; } public void setValue(Object val) { this.val=val; } public void showInfo() { System.out.println("Cache的ID是: "+id+" Cache的值是: "+val); } }


    问题4:上面你说的缓存是存在问题的,由于每次你都是统一刷新,有的数据刚刚在14min59s的时候上传的,你就得让它在1s后刷新吗?另外,有的数据变化的非常快。不能15min刷新的。而是须要没1min刷新一次,你这样做真的好吗?还有,有的数据在这15min中之内都不会用到,还有必要刷新吗?

    上述三个问题的确须要改进。那么我能够针对不同的缓存,而且在自由须要(发送请求+缓存不存在/失效)的时候才进行刷新。再进行优化。代码例如以下:

    /**
     *  项目名称:
     *  文件说明:创建一个缓存管理器 lcx
     *  主要特点:
     *  版本:1.0
     *  创建时间:2013-12-3
     **/
    package NBOffer;
    
    import java.util.Date;
    import java.util.HashMap;
    
    public class CacheManager {
    
    	static HashMap<String,Cache> cacheMap=new HashMap<String,Cache>();
    
    	public static Cache getCache(String id)
    	{
    		//对于不存在或者失效的缓存统一处理
    		if(cacheMap.get(id)==null||!cacheMap.get(id).isValid())
    		{
    			Object val=getFromDB(id);
    			Cache cache=new Cache(id,val);
    			cache.latest=new Date();
    			cacheMap.put(id, cache);
    		}
    		return cacheMap.get(id);
    	}
    
    	public static void putCache(Cache cache)
    	{
    		cache.latest=new Date();
    		cacheMap.put(cache.id, cache);
    	}
    
    	public static Object getFromDB(String id)
    	{
    		System.out.println("缓慢地从内存中读取id="+id+"相应的数据。。。

    "); return new String("value"+id); } public static void main(String[] args) { Cache cache1=new Cache("1","value1"); Cache cache2=new Cache("2","value2"); cache2.invalidTime=5000;//设置失效视角是5s CacheManager.putCache(cache1); CacheManager.putCache(cache2); try { Thread.sleep(6000); } catch (InterruptedException e) { e.printStackTrace(); } CacheManager.getCache("1"); CacheManager.getCache("2"); } } class Cache { String id;//相当于主键 Object val; Date latest;//近期刷新时间 long invalidTime=10000;//默认失效时间10s public Cache(String id) { new Cache(id,null); } public Cache(String id,Object val) { this.id=id; this.val=val; } public void setValue(Object val) { this.val=val; } /** * 推断如今缓存是否有效 * @return */ public boolean isValid() { return (new Date()).getTime()-latest.getTime()<invalidTime; } public void showInfo() { System.out.println("Cache的ID是: "+id+" Cache的值是: "+val); } }


    问题5:既然都做到这个份上了,那么关于缓存的几个名词都得说说了。

    缓存命中率:缓存命中率=从缓存中读数/(缓存读数+磁盘读数)。

    缓存失效:缓存超过了失效时间。过期了(也可能有其它原因)。

    缓存穿透:对于并不存在的数据。每次都会想DB发送请求,对DB的危害很大。

    缓存雪崩:对于某个失效的缓存在短时间内大量訪问,可能造成DB宕机。

    缓存算法:LRU、LFU、LIFO


    下一节,将针对不同的缓存算法进行研究。



  • 相关阅读:
    初始化生成linux sysfs(8)
    内存延迟监控系统组件
    数组代码First Missing Positive
    类文件Spring中空值的写法java教程
    状态键盘完美适应iOS中的键盘高度变化
    框架绑定JavaScript MVC框架PK:Angular、Backbone、CanJS与Ember
    域编码jquery的AJAX跨域请求及跨域请求的原理
    数据格式利用GSON接卸JSON数据
    网元查看一个无厘头的core dump问题定位
    类型应用oracle如何显示毫秒?
  • 原文地址:https://www.cnblogs.com/wgwyanfs/p/6845868.html
Copyright © 2011-2022 走看看