本文共 4067 字,大约阅读时间需要 13 分钟。
LinkedHashMap实现LRU以及其在spring-mvc中AbstractCachingViewResolver运用
一、LinkedHashMap实现LRU
1、LinkedHashMap有一个三个参数的构造函数,new LinkedHashMap<Object, View>(size, 0.75f, true),其中第三个参数accessOrder的作用是如果元素被访问的情况下,是否把元素添加到链表的尾部。结合LinkedHashMap的一个protected的removeEldestEntry方法,可以实现LRU(即最久没访问的移除)。
LinkedHashMap
从上面我们可以看到,元素添加abcd,如果没有使用下面的get方法,那么遍历的时候,结果也是abcd,但是get元素后,元素被移动到尾部,即等于这个元素移动到最新添加的位置,那么最后的结果就变成了cdab。
2、LinkedHashMap如何实现LRU,LRU是缓存淘汰策略里的一种,即最久没有使用进行移除,上面说的removeEldestEntry方法,如果返回ture,并且当容器的size大于初始给定的size时,那么就会移除掉链表的最前面的元素。看下面的案例。
// 如果对LinkedHashMap的removeEldestEntry方法进行复写,即大于容量,进行移除最先插入的。 LinkedHashMapmap2 = new LinkedHashMap (20, 0.75f, true){ protected boolean removeEldestEntry(Map.Entry eldest) { if (size() > 20) { return true; }else { return false; } } }; for (int i = 0; i < 30; i++) { map2.put(i+"", i); if(i>15) { map2.get(i+""); } } // 因为最后添加的15个元素持续被添加到map的结尾,那么最先添加10个元素就会被移除。 System.out.println(map2);
二、AbstractCachingViewResolver中的运用
AbstractCachingViewResolver是用来创建View的抽象基类,其创建功能是由子类模板方法实现的,它的主要功能就是缓存创建的View,但是为了不会无限的创建View,占用内存空间,这个类就利用LinkedHashMap的三个构造函数,在缓存1000个view后,会自动移除最久没访问的View对象。
细节实现是其内部有二个map变量,其中一个ConcurrentHashMap的实现用来快速读取view,如果我们无限缓存,就不必要引入另外一个LinkedHashMap了,另外一个map的作用就是同步创建更新删除View,并且LinkedHashMap加锁更新的时候也对ConcurrentHashMap进行了更新,这样我们就达到了利用一个非线程安全的LinkedHashMap利用加锁操作实现LRU的同时,对只提供访问的ConcurrentHashMap也进行了LRU的移除操作。
代码演示:
/** * MyCacheViewResolve的演示 * 创建30个view,当容量大于限制20个时,会进行移除,而viewCreationCache只有put操作访问,没有获取操作 * 即是移除最先添加的,最终结果就是10-29的view存在。 */ public static void main(String[] args) throws Exception { MyCacheViewResolve resolve = new MyCacheViewResolve(); for (int i = 0; i < 30; i++) { resolve.resolveViewName("view"+i); } System.out.println(resolve); // 10-29存在。 }}class MyCacheViewResolve { public static final int DEFAULT_CACHE_LIMIT = 20; private volatile int cacheLimit = DEFAULT_CACHE_LIMIT; private final MapviewAccessCache = new ConcurrentHashMap (DEFAULT_CACHE_LIMIT); @SuppressWarnings("serial") private final Map viewCreationCache = new LinkedHashMap (DEFAULT_CACHE_LIMIT, 0.75f, true) { @Override protected boolean removeEldestEntry(Map.Entry eldest) { if (size() > cacheLimit) { // 大于cachelimit时,reutrn true,能删除自身的,并且额外移除viewAccessCache的 viewAccessCache.remove(eldest.getKey()); return true; } else { return false; } } }; @Override public String toString() { return "MyCacheViewResolve [viewAccessCache=" + viewCreationCache + "]"; } public View resolveViewName(String viewName) throws Exception { View view = this.viewAccessCache.get(viewName); // 从concurrentMap缓存中取 if (view == null) { synchronized (this.viewCreationCache) { // 空就同步双检CreateMap创建 view = this.viewCreationCache.get(viewName); // if (view == null) { view = createView(viewName); if (view != null) { this.viewAccessCache.put(viewName, view); this.viewCreationCache.put(viewName, view); } } } } return view; } private View createView(String viewName) { return new View(viewName); } public void removeFromCache(String viewName) { synchronized (this.viewCreationCache) { this.viewAccessCache.remove(viewName); this.viewCreationCache.remove(viewName); } }}class View { private String name; public View(String name) { this.name = name; } @Override public String toString() { return "View [name=" + name + "]"; }}
转载地址:http://wruni.baihongyu.com/