最近了解了下缓存技术,主要分为内存缓存 和磁盘缓存,然后分布式里面有一些消息的推送,节点的一些处理。现在很多的用OSCache,EhCache 等等,资料很多,暂时就不多说了,我这里仅仅为了了解缓存框架的的知识,自己临时写一个缓存,后面可以实现AOP 和spring 结合。
实现功能:
1.数据都缓存到内存中
2.实现对每个元素Element的缓存时间进行控制
3.对每个缓存Cache 进行创建,以及销毁的管理
4.能对缓存存放个数进行管理
5.通过线程定时检查元素是否过期
6.可以定义缓存清除策略
实现思路:
1.Store 接口:定义常用的存取元素get,put的接口
2.AbstractStore:对接口基本方法进行实现
3.MemoryCache:对具体缓存的存取方法进行实现,并执行一定的逻辑控制
4.Cache:增加对缓存整体进行监听,销毁等操作
5.CacheManager:缓存管理器,负责管理缓存的容器
6.CacheConfiguration :一些缓存的配置属性
7.CheckManager:一些检查缓存内容的策略方法
8.EvictionType:枚举清空策略
9.CacheListener:缓存的监听,每次创建缓存就启动,然后定时检查缓存元素是否过期
10.Element: 元素的单元
package com.cache; import java.util.Collection; public interface Store { // 获得缓存名字 public String getName(); // 存放元素 public Element put(Element e); public Collection<Element> putAll(Collection<Element> elements); // 获取元素 public Element get(Object key); // 清除元素 public void clear(); // 移除元素 public void remove(Object key); public void removeAll(Object[] keys); // 获得的元素长度 public Integer size(); }
package com.cache; import java.util.Map; /** * 抽象类实现 */ public abstract class AbstractStore implements Store{ protected Map<Object, Element> map; public AbstractStore(){} public AbstractStore(Map<Object, Element> map){ this.map = map; } @Override public Element get(Object key) { Element e = map.get(key); return e; } public Map<Object, Element> getAll(){ return map; } @Override public void clear() { map.clear(); } @Override public Element put(Element e) { return map.put(e.getKey(), e); } @Override public void remove(Object key) { map.remove(key); } @Override public Integer size() { return map.size(); } @Override public void removeAll(Object[] keys) { for(int i =0;i<keys.length;i++){ remove(keys[i]); } } }
package com.cache; import java.util.Collection; import java.util.HashMap; import java.util.Map; /** * 缓存的基本方法 */ public class MemoryCache extends AbstractStore implements Store{ private final CacheConfiguration configure; private final static Map<Object, Element> map = new HashMap<Object, Element>(); private final CheckManager checkManager; // 暂时仅弄一个构造 public MemoryCache(CacheConfiguration configure){ super(map); this.configure = configure; this.checkManager = new CheckManager(configure, map); } @Override public String getName() { return configure.getCacheName(); } @Override public Collection<Element> putAll(Collection<Element> elements) { if(elements == null){ throw new NullPointerException("elements can't be null"); } check(elements.size()); for(Element e : elements){ putElementStatus(e); super.put(e); } return elements; } @Override public synchronized Element put(Element e) { check(1); putElementStatus(e); return super.put(e); } // 使用一次之后刷新使用过期时间,以及使用次数 // 并检查该元素是否过期 public void changeElement(Element e){ e.addHitCount(); if(!configure.getEternal()){ e.refreshLastAccessTime(); } } // 如果eternal 为true,表示元素永不过期,默认忽略最小元素控制 public void putElementStatus(Element e){ if(!configure.getEternal() && ! e.getIsOpen()){ e.setTimeToIdle(configure.getTimeToIdleSeconds()); e.setTimeToLive(configure.getTimeToLiveSeconds()); }else{ e.setTimeToIdle(0); e.setTimeToLive(0); } } @Override public Element get(Object key) { Element e = super.get(key); if(e != null){ if(!e.isExpired()){ changeElement(e); }else{ synchronized (this) { remove(e.getKey()); e = null; } } } return e; } // 检查元素 是否为空 public boolean checkElement(Element e){ if(e == null){ throw new NullPointerException("Element can't be null "); } if(e.getKey() == null){ throw new NullPointerException("Element key can't be null "); } return true; } @Override public synchronized void removeAll(Object[] keys) { super.removeAll(keys); } // 检查元素是否超过了 public void check(int checkSize){ if(checkSize <= 0){ return; } Object[] keys = checkManager.checkConfigure(checkSize); if(keys !=null) { removeAll(keys); } } }
package com.cache; /** * 这是对缓存 级的控制判断 */ public class Cache extends MemoryCache{ private CacheConfiguration configure; private CacheListener listener; public Cache(CacheConfiguration configure) { super(configure); this.configure = configure; if(!configure.getEternal() && configure.getIsNeedCacheCheckListener()){ listener = new CacheListener(this); listener.start(); } } public CacheConfiguration getConfigure() { return configure; } // 销毁 public void destory(){ try{ super.clear(); if(listener != null){ listener.interrupt(); listener.stop(); listener = null; } }catch (Exception e) { } } }
package com.cache; import java.util.HashMap; import java.util.Map; /** * 缓存管理类 */ public class CacheManager { // 默认单例 private CacheManager(){} private static class Singleton{ private static CacheManager instance = new CacheManager(); } public static CacheManager getInstance() { return Singleton.instance; } public static Map<String, Cache> MAP_NAMES_CACHE = new HashMap<String, Cache>(); // 存放 取出 缓存对象 public Cache getCache(String CacheName){ Cache cache = MAP_NAMES_CACHE.get(CacheName); return cache; } public void putCache(Cache cache){ if(cache != null && !MAP_NAMES_CACHE.containsKey(cache.getName())){ MAP_NAMES_CACHE.put(cache.getName(), cache); } } // 移除 public void remove(String cacheName){ Cache c = MAP_NAMES_CACHE.remove(cacheName); c.destory(); } // 关闭所有缓存 public void shutDown(){ removeAllCaches(); MAP_NAMES_CACHE.clear(); } // 移除所有 public void removeAllCaches(){ String [] cacheNames = getCacheNames(); for(String cacheName : cacheNames){ remove(cacheName); } } // 获得名字 public String[] getCacheNames(){ return MAP_NAMES_CACHE.keySet().toArray(new String[0]); } }
package com.cache; /** * * 这些属性来自于ehcache * 属于缓存级别的 一些控制 */ public class CacheConfiguration { // 缓存的名字 private String cacheName; // 是否需要缓存 循环检查 private Boolean isNeedCacheCheckListener = false; public Boolean getIsNeedCacheCheckListener() { return isNeedCacheCheckListener; } public void setIsNeedCacheCheckListener(Boolean isNeedCacheCheckListener) { this.isNeedCacheCheckListener = isNeedCacheCheckListener; } // 内存最大缓存对象数 private Integer maxElementsInMemory; // 缓存元素是否永久有效,一旦设置true ,失效时间 将不起作用,默认false private Boolean eternal = false; // 设置缓存在失效前的允许闲置时间。仅当缓存不是永久有效时使用(timeToLiveSeconds != 0) // 可选属性,默认值是0,也就是可闲置时间无穷大。 private Integer timeToIdleSeconds = 0; // 设置缓存长允许存活时间,最大时间介于创建时间和失效时间之间. // 仅当缓存不是永久有效时使用,默认值是0,也就是缓存存活时间无穷大。 private Integer timeToLiveSeconds = 0; // 对象检测线程运行的时间间隔。表示对象状态的线程多长时间运行一次 // 这里暂时用来对内存对象的检查 private Integer diskExpiryThreadIntervalSeconds = 120; // 如果缓存满了,执行清空策略 // 可选FIFO,LFU 这里要用枚举类型 // FIFO :先进先出 // LFU:最少使用,一直以来最少被使用的,缓存缓存有一个hit属性,清除hit最小的 // LRU:最近最少使用,缓存元素有个时间戳,当缓存容量满了,而又需要腾出新地方 // 来缓存的时候,那么现有的缓存缓存中时间戳离当前时间最远的缓存将被清除缓存 private String memoryStoreEvictionPolicy = EvictionType.LRU.name(); // 暂时未用 // 当缓存数量达到最大值时,允许将缓存写入到磁盘 private Boolean overflowToDisk = false; // 磁盘中最大的缓存对象数,若是0表示无穷大 private Integer maxElementsOnDisk = 0; // 是否在磁盘上持久化,默认false private Boolean diskPersistent = false; public CacheConfiguration() { } public CacheConfiguration(String cacheName,Integer maxElementsInMemory, Boolean eternal,Integer timeToIdleSeconds,Integer timeToLiveSeconds, Integer diskExpiryThreadIntervalSeconds) { this.cacheName = cacheName; this.maxElementsInMemory = maxElementsInMemory; this.eternal = eternal; this.timeToIdleSeconds = timeToIdleSeconds; this.timeToLiveSeconds = timeToLiveSeconds; this.diskExpiryThreadIntervalSeconds = diskExpiryThreadIntervalSeconds; } public String getCacheName() { return cacheName; } public void setCacheName(String cacheName) { this.cacheName = cacheName; } public Integer getMaxElementsInMemory() { return maxElementsInMemory; } public void setMaxElementsInMemory(Integer maxElementsInMemory) { this.maxElementsInMemory = maxElementsInMemory; } public Boolean getEternal() { return eternal; } public void setEternal(Boolean eternal) { this.eternal = eternal; } public Integer getTimeToIdleSeconds() { return timeToIdleSeconds; } public void setTimeToIdleSeconds(Integer timeToIdleSeconds) { this.timeToIdleSeconds = timeToIdleSeconds; } public Integer getTimeToLiveSeconds() { return timeToLiveSeconds; } public void setTimeToLiveSeconds(Integer timeToLiveSeconds) { this.timeToLiveSeconds = timeToLiveSeconds; } public Boolean getOverflowToDisk() { return overflowToDisk; } public void setOverflowToDisk(Boolean overflowToDisk) { this.overflowToDisk = overflowToDisk; } public Integer getMaxElementsOnDisk() { return maxElementsOnDisk; } public void setMaxElementsOnDisk(Integer maxElementsOnDisk) { this.maxElementsOnDisk = maxElementsOnDisk; } public Boolean getDiskPersistent() { return diskPersistent; } public void setDiskPersistent(Boolean diskPersistent) { this.diskPersistent = diskPersistent; } public Integer getDiskExpiryThreadIntervalSeconds() { return diskExpiryThreadIntervalSeconds; } public void setDiskExpiryThreadIntervalSeconds( Integer diskExpiryThreadIntervalSeconds) { this.diskExpiryThreadIntervalSeconds = diskExpiryThreadIntervalSeconds; } public String getMemoryStoreEvictionPolicy() { return memoryStoreEvictionPolicy; } public void setMemoryStoreEvictionPolicy(String memoryStoreEvictionPolicy) { this.memoryStoreEvictionPolicy = memoryStoreEvictionPolicy; } }
package com.cache; import java.io.Serializable; /** * 缓存元素,所对应的属性 */ @SuppressWarnings("serial") public class Element implements Serializable { static final long ONE_SECOND = 1000L; private Object key; private Object value; // 使用次数 private volatile long hitCount = 0; // 这些属性是单个元素的属性控制 // 是否使用单独元素控制 private Boolean isOpen = false; // 从创建时间开始后,还能存活时间,0 表示一直存活,超时时间=timeToLive + CreationTime private volatile int timeToLive = 0; // 从最近即(min(CreationTime,LastAccessTime)) 后还剩余的时间 private volatile int timeToIdle = 0; // 创建时间 private transient long creationTime; // 最后一次使用的时间 private transient long lastAccessTime; // 最后更新时间 private volatile long lastUpdateTime; // 表示是否使用cache 级别的控制,还是元素级别的控制,这里暂时不用 private volatile boolean cacheDefaultLifespan = true; public Element(final Object key, final Object value){ init(key,value); } public Element(final Object key, final Object value,Boolean isOpen){ init(key, value); this.isOpen = isOpen; } private void init(final Object key, final Object value){ this.key = key; this.value = value; this.creationTime = System.currentTimeMillis(); this.lastAccessTime = System.currentTimeMillis(); } public Object getKey() { return key; } public void setKey(Object key) { this.key = key; } public Object getValue() { return value; } public long getHitCount() { return hitCount; } public void setHitCount(long hitCount) { this.hitCount = hitCount; } public void addHitCount(){ hitCount += 1; } public int getTimeToLive() { return timeToLive; } public void setTimeToLive(int timeToLive) { this.timeToLive = timeToLive; } public int getTimeToIdle() { return timeToIdle; } public void setTimeToIdle(int timeToIdle) { this.timeToIdle = timeToIdle; } public long getCreationTime() { return creationTime; } public void setCreationTime(long creationTime) { this.creationTime = creationTime; } public long getLastAccessTime() { return lastAccessTime; } public void setLastAccessTime(long lastAccessTime) { this.lastAccessTime = lastAccessTime; } public long getLastUpdateTime() { return lastUpdateTime; } public void setLastUpdateTime(long lastUpdateTime) { this.lastUpdateTime = lastUpdateTime; } public boolean isCacheDefaultLifespan() { return cacheDefaultLifespan; } public void setCacheDefaultLifespan(boolean cacheDefaultLifespan) { this.cacheDefaultLifespan = cacheDefaultLifespan; } public void setValue(Object value) { this.value = value; } public Boolean getIsOpen() { return isOpen; } public void setIsOpen(Boolean isOpen) { this.isOpen = isOpen; } /** * 判断元素 是否过期 * @return */ public boolean isExpired() { if (isEternal()) { return false; } // 获得过期时间 long expirationTime = getExpirationTime(); long now = System.currentTimeMillis(); return now > expirationTime; } // 是否是不会过期 public boolean isEternal() { return (0 == timeToIdle) && (0 == timeToLive); } // 计算过期时间 public long getExpirationTime() { if (isEternal()) { return Long.MAX_VALUE; } // 存活时间 long expirationTime = 0; long ttlExpiry = creationTime + getTimeToLive() * ONE_SECOND; // 到期时间 long mostRecentTime = Math.max(creationTime, lastAccessTime); long ttiExpiry = mostRecentTime + getTimeToIdle() * ONE_SECOND; // 如果仅仅设置了timeToLive,那么时间以 timeToLive的计算为准 if (getTimeToLive() != 0 && (getTimeToIdle() == 0 || lastAccessTime == 0)) { expirationTime = ttlExpiry; } else if (getTimeToLive() == 0) { // 如果仅仅设置了 timeToIdle,那么时间以timeToIdle 的计算为准 expirationTime = ttiExpiry; } else { // 如果两种都设置了,那么取小的一个为准 expirationTime = Math.min(ttlExpiry, ttiExpiry); } return expirationTime; } // 刷新最后一次使用时间 public void refreshLastAccessTime(){ lastAccessTime = System.currentTimeMillis(); } }
package com.cache; import java.util.Iterator; import java.util.Map; /** * 检查的的一些方式 * @author Administrator * */ public class CheckManager { protected CacheConfiguration configure; protected Map<Object, Element> map; public CheckManager(CacheConfiguration configure,Map<Object, Element> map) { this.map = map; this.configure = configure; } // 添加检查元素是否已经到达最大值,或者已经过期 public Object[] checkConfigure(int elementSize){ int removeSize = map.size()+elementSize - configure.getMaxElementsInMemory(); // 判断缓存是否已满 if(removeSize > 0){ // 按规则删除元素,这里不写磁盘 if(!configure.getDiskPersistent()){ return removeElementByEvictionType(removeSize); } } return null; } // 根据方式移除 public Object[] removeElementByEvictionType(int removeSize){ if(configure.getMemoryStoreEvictionPolicy().equals(EvictionType.LRU.name())){ return removeElementByLRU(removeSize); } return null; } // 暂时默认根据最少使用次数进行删除 private Object[] removeElementByLRU(int removeSize){ Object keys[] = new Object[removeSize]; long hits[] = new long[removeSize]; Iterator<?> it = map.keySet().iterator(); // 找出hit值最小的 removeSize 个元素 int index = 0; while(it.hasNext()){ Object key = it.next(); Element e = map.get(key); long hit = e.getHitCount(); if(index < removeSize){ hits[index] = hit; keys[index] = key; index ++; }else{ long pos = getMinIndex(hits, hit); if(pos >= 0){ keys[(int) pos] = key; } } } return keys; } private long getMinIndex(long hits[],long hit){ long pos = -1; for(int i = 0;i<hits.length;i++){ if(hits[i] > hit){ hits[i] = hit; pos = i;; } } return pos; } }
package com.cache; /** * 几种删除策略 */ public enum EvictionType { LRU,LFU,FIFO }
package com.cache; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; /** * 循环检查元素 * @author Administrator * */ public class CacheListener extends Thread{ private Cache cache; private volatile boolean stop = false; private volatile long ONE_SECOND = 1000; public boolean isStop() { return stop; } public void setStop(boolean stop) { this.stop = stop; } public CacheListener(Cache cache) { this.cache = cache; } @Override public void run() { long time = cache.getConfigure().getDiskExpiryThreadIntervalSeconds(); try { while(!stop){ sleep(time*ONE_SECOND); threadCheckElement(); } } catch (InterruptedException e1) { e1.printStackTrace(); } } public void destory(){ ONE_SECOND = 0; stop = true; } public void threadCheckElement(){ List<Object> keys = new ArrayList<Object>(); Map<Object, Element> map = cache.getAll(); if(map != null && map.size() > 0){ for(Entry<Object, Element> e0: map.entrySet()){ Element e = e0.getValue(); if(e != null && e.isExpired()){ keys.add(e0.getKey()); } } } cache.removeAll(keys.toArray()); } }
package com.test; import com.cache.Cache; import com.cache.CacheConfiguration; import com.cache.CacheManager; import com.cache.Element; public class Test { /** * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { CacheManager cm = CacheManager.getInstance(); Cache c1 = new Cache(getConfigure()); // 最大放5个 putTestE1(c1); cm.putCache(c1); // 只有2 的hit 值最小,因此超过了就被移除了 null System.out.println(c1.get(2)); // 想存放6了,实际数据只有5个 System.out.println("总数:"+c1.size()); // 休息3秒,然后使用 Thread.sleep(1000*3); System.out.println("刷新:"+c1.get(1)); // 然后继续休息 Thread.sleep(1000*3); System.out.println("使用着的元素:"+c1.size()); Thread.sleep(1000*15); System.out.println("时间太久,全部过期"+c1.size()); //cm.shutDown(); } public static CacheConfiguration getConfigure(){ CacheConfiguration c = new CacheConfiguration(); c.setCacheName("Test1"); // 最多存放5个元素 c.setMaxElementsInMemory(5); // 假设5秒不用就过期,这两个时间一般默认选小的一个执行,最长时间是 存活的总时间 c.setTimeToIdleSeconds(5); // 假设最长能存活115秒 c.setTimeToLiveSeconds(115); // 6秒 检查一次过期 c.setDiskExpiryThreadIntervalSeconds(6); return c; } public static void putTestE1(Cache c1){ c1.put(new Element(1, 2)); c1.get(1); c1.put(new Element(2, 2)); //c1.get(2); c1.put(new Element(3, 2)); c1.get(3); c1.put(new Element(4, 2)); c1.get(4); c1.put(new Element(5, 2)); c1.get(5); c1.put(new Element(6, 2)); } }
小结:
1.这里是看了一些Ehcache 的源码,加上自己的思路写的,仅做第一次尝试之用
2.关于磁盘缓存 和 分布式 的东西这里是没有的,包括异常各种处理,这里都是没有的
3.关于缓存管理,这里每个cache 都有一个线程,是需要改进的,比较消耗资源
4.测试代码,我测试了一部分,会有遗漏的,留点有兴趣的去搞吧。
5.有问题请多指点,代码,和ehcache 已经在里面的,可以参考。
相关推荐
在Android开发中,为了优化用户体验,提高应用性能,通常会采用文件缓存和内存缓存技术,特别是处理像ListView这样的滚动列表组件加载网络图片时。本文将深入探讨这两种缓存机制,以及如何解决图片错位问题。 首先...
在Android中,常见的内存缓存实现是使用`LruCache`类,它是Android提供的一个基于最近最少使用(LRU)算法的缓存。通过限制缓存的最大大小,当内存不足时,会自动移除最近最少使用的数据。内存缓存可以显著提高图片...
为了实现内存缓存,可以使用SharedPreferences或Android的WeakReference机制。SharedPreferences是一个轻量级的数据存储方式,适合保存简单的键值对,而WeakReference可以帮助我们避免内存泄漏,因为它会在对象不再...
本文将深入探讨内存缓存的基本原理、应用场景以及内存缓存技术在实际开发中的具体实现。 #### 二、内存与缓存的作用关系 内存缓存技术的核心思想是“以空间换时间”,即通过预先在内存中存储数据,以减少或消除对...
本教程将深入探讨这两种缓存机制的使用,并提供一个包含实例代码的Demo下载。 ### 一、NSCache `NSCache`是苹果提供的轻量级内存缓存系统,用于临时存储不重要的数据。它与`NSMutableDictionary`类似,但有一些...
主动式内存缓存是互联网服务中用于提高数据读取速度、减少数据库压力的一种常用技术。它将最常访问的数据保存在内存中,使得数据读取速度大幅度提升。然而,实现主动式内存缓存需要解决众多技术难题,比如如何保证...
随手写了一个TreeNode,顺道实现了个对应的内存缓存框架,适用于数据量不大,更新也少但是反复要读的数据,比如模块信息/组织结构/频道栏目/权限等。 PS:Java是可以直接操作内存的,只是现在的框架整合让人退化了。...
为了解决这个问题,本文将介绍如何对图片资源进行优化,并且实现内存双缓存磁盘缓存。 一、图片资源优化 在加载图片时,需要对图片资源进行优化,以减少内存的占用。常见的图片资源优化方法有以下几种: 1. 缩放...
内存硬盘缓存的工作原理是这样的:当计算机需要访问硬盘上的数据时,首先会检查该数据是否已经在内存缓存中。如果在,那么数据的读取速度将显著提高,因为内存的读取速度远超硬盘。如果数据不在内存中,软件会先将...
Volley+Cache 实现网络缓存以及内存缓存
- **LruCache**: Android SDK提供的一种基于最近最少使用原则(LRU)的内存缓存实现。当内存空间不足时,会自动移除最近最少使用的数据。 - **DiskLruCache**: 一种磁盘缓存实现,同样基于LRU策略。它在磁盘上创建...
在Android中,`LruCache`被引入作为内存缓存的一个解决方案,因为它能够帮助开发者有效地管理内存,避免内存泄漏,并减少因大量图片加载导致的ANR(Application Not Responding)问题。 1. **理解内存缓存** 内存...
Go-kache是一个基于Go语言实现的轻量级内存缓存库,它的设计目标是提供一个简单易用且高效的缓存解决方案。在理解Go-kache的工作原理和应用之前,我们需要先了解缓存在计算机科学中的基本概念。 缓存是一种存储技术...
在Windows操作系统中,内存管理是一个非常重要的方面。Windows实现按需调页的虚拟内存机制,使得应用程序可以使用超过物理内存容量的虚拟内存。此外,Windows还使用了页面文件来扩展物理内存的容量。 在Java中,...
一个基于go语言实现的内存缓存,通过lru算法实现定时任务、
在C语言中实现内存乒乓缓冲机制和消息分发机制是计算机科学中用于提高数据处理效率的重要技术手段。本知识点将详细解读这些概念,并解析给定代码段中实现的具体策略。 ### 内存乒乓缓存机制 内存乒乓缓冲机制是一种...
`ImagesCache`项目可能包含了一个机制,自动在内存和SDCard之间进行图片的迁移和同步。 防止OOM: OOM(Out Of Memory)错误通常发生在Android应用尝试分配超出可用内存的内存时。图片加载是引发OOM的主要原因之一...
在Android应用开发中,用户登录功能是不可或缺的一部分,而实现一个高效、安全的登录系统尤为重要。本示例将探讨如何在Android中实现类似QQ的帐号密码登录机制,并结合内存缓存来优化用户体验。我们将深入讨论以下几...
Volley框架二次封装,实现了带Cookie的Get和Post请求,图片加载和图片缓存(内存缓存,SD缓存,内存SD双缓存.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。