最近在看mybatis的源代码,发现了mybatis中实现的LruCache使用到了LinkedHashMap,所以就探究了一下LinkedHashMap是如何支持Lru缓存的

LinkedHashMap内部维护了一个所有的Entity的双向链表

同时构造方法可以设置Iterator的时候,是按照插入的顺序排序还是按照访问的顺序排序

默认是按照插入的顺序来排序的,在构造方法里边可以设置按照访问的顺序来排序

那究竟按照访问的顺序来排序是什么意思呢?

LinkedHashMap的get(key)方法是自己实现的,并没有从HashMap里边继承,我们看看get(Key)方法的实现是什么样子的

我们看afterNodeAccess()方法是如何实现的

这个方法主要就是移动双向链表的指针,将传入的结点移动到LinkedHashMap维护的双向链表的末尾,这样每次通过get(key)方法访问一个元素,这个元素就会被移动到双向链表的末尾,按照访问的顺序来排序,就是每次通过Iterator来遍历keySet或者是EntrySet的时候,访问过的元素会出现在最后边(因为LinedHashMap的Iterator遍历的时候,遍历的是内部的双向链表,从头结点,遍历到尾结点)

顺着这样的思路,如果在满足一定条件的情况下,移除掉双向链表的头结点,这样就实现了一个LruCahe

其实LinkedHashMap已经为我们提供了这样的方法,LinkedHashMap中有一个方法removeEldestEntry(entry) 我们只需要覆盖这个方法,根据我们自己的需求在一定条件下返回true,这样就实现了LruCache

改方法的默认实现是返回false

protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {

return false;

}

LinkedHashMap的afterNodeInsertion()方法会根据其他条件以及removeEldestEntry的返回值来决定是否删除到双向链表的表头元素

依据此,我们使用LinkedHashMap来实现一个最简单的Lru缓存如下:

import org.junit.Test;

import java.util.LinkedHashMap;
import java.util.Map;
public class TestCache {
@Test
public void testLinkedHashMap() {
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>(5, 0.75F, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
//当LinkHashMap的容量大于等于5的时候,再插入就移除旧的元素
return this.size() >= 5;
}
};
map.put("aa", "bb");
map.put("cc", "dd");
map.put("ee", "ff");
map.put("gg", "hh");
print(map);
map.get("cc");
System.out.println("===================================");
print(map); map.get("ee");
map.get("aa");
System.out.println("====================================");
map.put("ss","oo");
print(map);
} void print(LinkedHashMap<String, String> source) {
source.keySet().iterator().forEachRemaining(System.out::println);
}
}

Mybatis中的Lrucache实现也是类似的思路,比较简单,下边是关键的代码:

构造方法中调用了setSize()方法,默认缓存1024个元素

public LruCache(Cache delegate) {
this.delegate = delegate;
setSize(1024);
}

setSize()方法中初始化了HashMap,并实现了removeEldestEntry()方法

public void setSize(final int size) {
keyMap = new LinkedHashMap<Object, Object>(size, .75F, true) {
private static final long serialVersionUID = 4267176411845948333L; @Override
protected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {
boolean tooBig = size() > size;
if (tooBig) {
eldestKey = eldest.getKey();
}
return tooBig;
}
};
}

如何使用LinkedHashMap来实现一个LruCache的更多相关文章

  1. 通过反射,获取linkedHashMap的最后一个键值对。对map按照值进行排序。

    1:通过反射,获取linkedHashMap的最后一个键值对. Map<Integer, Integer> map = new LinkedHashMap<>(); Field ...

  2. 使用LinkedHashMap来实现一个使用LRU(Least Recently Used)算法的cache

    removeEldestEntry在使用put或者putAll方法插入一个新的entry到map中时被调用,是否要删除年老的entry取决于是否满足既定的条件(比如本例中的条件:MAP中entry数量 ...

  3. 小心LinkedHashMap的get()方法(转)

    这是一个来自实际项目的例子,在这个案例中,有同事基于jdk中的LinkedHashMap设计了一个LRUCache,为了提高性能,使用了 ReentrantReadWriteLock 读写锁:写锁对应 ...

  4. Java 自定义实现 LRU 缓存算法

    背景 LinkedHashMap继承自HashMap,内部提供了一个removeEldestEntry方法,该方法正是实现LRU策略的关键所在,且HashMap内部专门为LinkedHashMap提供 ...

  5. LinkedHashMap 与 LRUcache

    LRU 缓存介绍 我们平时总会有一个电话本记录所有朋友的电话,但是,如果有朋友经常联系,那些朋友的电话号码不用翻电话本我们也能记住,但是,如果长时间没有联系了,要再次联系那位朋友的时候,我们又不得不求 ...

  6. Android开发学习之路-LruCache使用和源码分析

    LruCache的Lru指的是LeastRecentlyUsed,也就是近期最少使用算法.也就是说,当我们进行缓存的时候,如果缓存满了,会先淘汰使用的最少的缓存对象. 为什么要用LruCache?其实 ...

  7. 一起写一个Android图片加载框架

    本文会从内部原理到具体实现来详细介绍如何开发一个简洁而实用的Android图片加载缓存框架,并在内存占用与加载图片所需时间这两个方面与主流图片加载框架之一Universal Image Loader做 ...

  8. android之LruCache源代码解析

    移动设备开发中,因为移动设备(手机等)的内存有限,所以使用有效的缓存技术是必要的.android提供来一个缓存工具类LruCache,开发中我们会经经常使用到,以下来他是怎样实现的. 在package ...

  9. LinkedHashMap相关信息介绍(转)

    Java中的LinkedHashMap此实现与 HashMap 的不同之处在于,后者维护着一个运行于所有条目的双重链接列表.此链接列表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序 ...

随机推荐

  1. H3C505

    H3C505 1.立方体案例 2.3D变换 1)景深透视 prospective:xx px; 设置观察元素的距离,数值小时,在元素内进行观察 prospective-origin: xpx,xpx ...

  2. dubbo+zipkin调用链监控(二)

    *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...

  3. itchat

    # -*- coding: utf-8 -*- """ Spyder Editor This is a temporary script file. "&quo ...

  4. centos找不到环境变量 -bash: ls: command not found

    #在系统中输入命令,报如下错误: [root@a1 work]# ll-bash: ls: command not found #昨时解决办法:export PATH=/usr/local/sbin: ...

  5. Android:android studio快捷键大全

    一.常用快捷键 1.Ctrl+E,可以显示最近编辑的文件列表 2.Shift+Click可以关闭文件 3.Ctrl+[或]可以跳到大括号的开头结尾 4.Ctrl+Shift+Backspace可以跳转 ...

  6. HOWTO: 如何利用Avizo或Amira计算孔隙率(Porosity)

    在做三维可视化数据处理过程中,我们经常要提取的一个基本信息就是孔隙率.在今天的文章中我们要分享两个信息,一个是如何利用Avizo或Amira进行孔隙率计算:另外是关于Avizo 8.0中孔隙率计算异常 ...

  7. numpy.trace对于三维以上array的解析

    numpy.trace是求shape的对角线上的元素的和,具体看 https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.t ...

  8. cleanmymacchinese下载链接

    由于新的chinese版本还没有公开发布下载链接,所以找到如下地址 https://dl.devmate.com/com.macpaw.zh.CleanMyMac3/CleanMyMacChinese ...

  9. Swagger Annotation 详解(建议收藏)

    转载:https://www.jianshu.com/p/b0b19368e4a8 在软件开发行业,管理文档是件头疼的事.不是文档难于撰写,而是文档难于维护,因为需求与代码会经常变动,尤其在采用敏捷软 ...

  10. String类源码解析

    1. String是使用char[]数组来存储的,并且String值在创建之后就不可以改变了.char[]数组的定义为: /** The value is used for character sto ...