博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
LinkedHashMap实现LRU以及其在spring-mvc中AbstractCachingViewResolver运用
阅读量:4074 次
发布时间:2019-05-25

本文共 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
map = new LinkedHashMap
(100, 0.75f, true); map.put("1", "a"); map.put("2", "b"); map.put("3", "c"); map.put("4", "d"); for (Iterator
iterator = map.values().iterator(); iterator.hasNext();) { String name = (String) iterator.next(); System.out.print(name); // 默认是abcd } System.out.println("........................................................"); map.get("1"); map.get("2"); System.out.println(map); for (Iterator iterator = map.values().iterator(); iterator.hasNext();) { String name = (String) iterator.next(); System.out.print(name); // 变成了cdab 即被访问后,元素的顺序被放到了最后面。 }

从上面我们可以看到,元素添加abcd,如果没有使用下面的get方法,那么遍历的时候,结果也是abcd,但是get元素后,元素被移动到尾部,即等于这个元素移动到最新添加的位置,那么最后的结果就变成了cdab。

2、LinkedHashMap如何实现LRU,LRU是缓存淘汰策略里的一种,即最久没有使用进行移除,上面说的removeEldestEntry方法,如果返回ture,并且当容器的size大于初始给定的size时,那么就会移除掉链表的最前面的元素。看下面的案例。

// 如果对LinkedHashMap的removeEldestEntry方法进行复写,即大于容量,进行移除最先插入的。		LinkedHashMap
map2 = 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 Map
viewAccessCache = 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/

你可能感兴趣的文章
阶乘、阶乘之和的函数式风格实现
查看>>
SVN部署(本地)
查看>>
SVN部署(远程)服务器篇
查看>>
SVN部署(远程)客户端篇
查看>>
CLAPACK动态调用
查看>>
MFC中由左键单击模拟左键双击引起的问题
查看>>
一个指针的引用引发的血案
查看>>
vector的push_back对于拷贝构造和赋值操作的调用
查看>>
OpenSees开发(一)windows 上编译opensees (使用vs2005)
查看>>
小议函数指针
查看>>
WEB服务器、应用程序服务器、HTTP服务器区别
查看>>
用户名称修改的完美解决方法
查看>>
discuz 3 头像显示不成功
查看>>
手动添加uc应用及其 提示notelist表缺少appX字段的处理方法
查看>>
Discuz!X3.2 uc_server密码正确无法登录的解决方法
查看>>
discuz登录admin后台老是自动跳出来
查看>>
discuz限制用户查看购买记录
查看>>
MFC画图
查看>>
一个GDI双缓冲类
查看>>
InvalidateRect函数
查看>>