LinkedHashMap 的理解以及借助其实现LRU
LinkedHashMap 的理解以及借助其实现LRU
LinkedHashMap中有一个参数 accessOrder,这个参数定义了LinkedHashMap的访问顺序。
LinkedHashMap中继承了Node,给Node新增了2个新的属性before和after
static class Entry<K,V> extends HashMap.Node<K,V> {Entry<K,V> before, after;Entry(int hash, K key, V value, Node<K,V> next) {super(hash, key, value, next);}
}
put方法
put方法LinkedHashMap没有重写,使用的是HashMap的put,但是其中还是有不同,重写了其中几个方法,先看代码:
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {Node<K,V>[] tab; Node<K,V> p; int n, i;if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;if ((p = tab[i = (n - 1) & hash]) == null)//重写newNode方法tab[i] = newNode(hash, key, value, null);else {Node<K,V> e; K k;if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))e = p;else if (p instanceof TreeNode)e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);else {for (int binCount = 0; ; ++binCount) {if ((e = p.next) == null) {//重写newNode方法p.next = newNode(hash, key, value, null);if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(tab, hash);break;}if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}if (e != null) { // existing mapping for keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;//重写afterNodeAccessafterNodeAccess(e);return oldValue;}}++modCount;if (++size > threshold)resize();//重写afterNodeInsertionafterNodeInsertion(evict);return null;
}
看下重写的这几个方法:
newNode方法:
实现了每调用一次newNode方法,利用before和after节点可把新节点插入到队尾。保证了一种调用newNode的顺序。
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {LinkedHashMap.Entry<K,V> p =new LinkedHashMap.Entry<K,V>(hash, key, value, e);linkNodeLast(p);return p;
}private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {LinkedHashMap.Entry<K,V> last = tail;tail = p;if (last == null)head = p;else {p.before = last;last.after = p;}
}
afterNodeAccess方法:
在put一个已存在的key时且 accessOrder 为true 时会调用,此方法会这个节点放到队伍的最后。
void afterNodeAccess(Node<K,V> e) { // move node to lastLinkedHashMap.Entry<K,V> last;if (accessOrder && (last = tail) != e) {LinkedHashMap.Entry<K,V> p =(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;p.after = null;if (b == null)head = a;elseb.after = a;if (a != null)a.before = b;elselast = b;if (last == null)head = p;else {p.before = last;last.after = p;}tail = p;++modCount;}
}
afterNodeInsertion方法
有新的Node时会调用,默认removeEldestEntry返回false,所以这一个方法什么都不做。不过可以看下如果返回不是false,则会删除head节点。这也是实现LRU的一个基础。
void afterNodeInsertion(boolean evict) { // possibly remove eldestLinkedHashMap.Entry<K,V> first;if (evict && (first = head) != null && removeEldestEntry(first)) {K key = first.key;removeNode(hash(key), key, null, false, true);}
}protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {return false;
}
get方法
get方法 会在accessOrder为true时把这个节点放到以before ,after为基础的一个双向链表的队尾。
public V get(Object key) {Node<K,V> e;if ((e = getNode(hash(key), key)) == null)return null;if (accessOrder)afterNodeAccess(e);return e.value;
}
foreach,keySet,entrySet遍历方法
所有的遍历在LinkedHashMap里都会重写,都是按照以before ,after为基础的一个双向链表的顺序进行遍历。
accessOrder变量
从上面的get和put过程可以发现,access为false时,则双向链表会变成一个按照插入顺序的链表。如果为true,则会变成按照访问顺序的一个链表。
如何借助LinkedHashMap来实现LRU
上面看到有一个方法removeEldestEntry,默认返回false,这个方法,顾名思义就是删除双向链表最开头的头部节点。
所以要实现LRU,只需要这样即可:
传入accessOrder为true,重写removeEldestEntry,根据缓存目标设置的size来决定在达到多少时来进行remove。
class LRU<K,V> extends LinkedHashMap<K, V>{public LRU(int initialCapacity,float loadFactor,boolean accessOrder) {super(initialCapacity,loadFactor,accessOrder);}@Overrideprotected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {if (this.size()>4) {return true;}return super.removeEldestEntry(eldest);}}
LinkedHashMap 的理解以及借助其实现LRU相关推荐
- 【大话Java面试】-如何通俗易懂的理解Redis的回收算法LRU?
如何通俗易懂的理解LRU算法? 1.LRU是什么? LRU全称Least Recently Used,也就是最近最少使用的意思,是一种内存管理算法,最早应用于Linux操作系统. LRU算法基于一种假 ...
- 看动画理解「链表」实现LRU缓存淘汰算法
前几节学习了「链表」.「时间与空间复杂度」的概念,本节将结合「循环链表」.「双向链表」与 「用空间换时间的设计思想」来设计一个很有意思的缓存淘汰策略:LRU缓存淘汰算法. 循环链表的概念 如上图所示: ...
- java mysql lru_Java集合详解5:深入理解LinkedHashMap和LRU缓存
今天我们来深入探索一下LinkedHashMap的底层原理,并且使用linkedhashmap来实现LRU缓存. 摘要:HashMap和双向链表合二为一即是LinkedHashMap.所谓Linked ...
- Java集合详解5:深入理解LinkedHashMap和LRU缓存
<Java集合详解系列>是我在完成夯实Java基础篇的系列博客后准备开始写的新系列. 这些文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查 ...
- 彻底理解HashMap及LinkedHashMap
欢迎关注方志朋的博客,回复"666"获面试宝典 来源:https://blog.csdn.net/fuzhongmin05/article/details/104355841 Ha ...
- LinkedHashMap实现LRU缓存算法
缓存这个东西就是为了提高运行速度的,由于缓存是在寸土寸金的内存里面,不是在硬盘里面,所以容量是很有限的. LRU这个算法就是把最近一次使用时间离现在时间最远的数据删除掉. 先说说List:每次访问一个 ...
- LinkedHashMap实现LRU算法
LinkedHashMap 概述 笔者曾提到,HashMap 是 Java Collection Framework 的重要成员,也是Map族(如下图所示)中我们最为常用的一种.不过遗憾的是,Hash ...
- java lru lfu_Java集合之LinkedHashMap实现LRU,LFU,FIFO算法
LinkedHashMap=双向链表+HashMap,存储相比HashMap会多了一个前节点,后节点. LinkedHashMap简介 LinkedHashMap主要是通过HashMap+双向链表来实 ...
- 面试官:说说Innodb中LRU怎么做的?
引言 某日,小编去面试(纯属瞎编),有了如下对话 面试官:"懂mysql吧,知道CPU在读硬盘上数据的时候,是怎么解决CPU和硬盘速度不一致问题么?"我:"懂啊,mysq ...
最新文章
- 清理mysql创建的游戏_Linux定时清理游戏log及mysql定时任务删除游戏日志数据的步骤...
- 怎样使 Python 输出时不换行?
- 【杂谈】如何使用有三AI生态学习计算机视觉和自然语言处理等内容
- 记录解决二次编码问题
- 韩研究人员声称:创造出了一块“不可破坏”的芯片!
- Docker-compose配置Mysql,Redis,MongoDB
- java hive demo_java 操作hive通过jdbc
- GO国内镜像加速模块下载
- 面向对象设计原则之5-接口隔离原则
- Android热修复Java类_Android 热修复(一)
- python中try怎么用_python下try
- 正确使用日志的10个技巧(转)
- Android知识散点
- 网络安全[脚本小子] -- SSI注入
- 基金经理的13年期货感悟(一)
- 格林尼治时间与本地时间转换
- r76800h怎么样r7 6800h参数
- 远程办公:通过cpolar内网穿透,远程桌面控制家里公司内网电脑
- 网络系统管理技能大赛知识点一
- 你有试过AutoCAD的超级填充功能吗?
热门文章
- 机器人简化图画手绘图_高通推出全新RB3 机器人平台,年内支持5G连接
- java程序阅读技巧_Java程序员阅读源码的小技巧,原来大牛都是这样读的,赶紧看看!...
- android 内存占用大 卡顿,安卓手机用久了就会卡顿?那是内存使用率高了,你需要这么做...
- js调用c语言程序设计,HTML页面,测试JS对C函数的调用简单实例
- mint java_Linux Mint19安装jdk1.8.0.191过程
- 五十九、如何求N个数的最大公约数和最小公倍数
- torch中的topk()函数
- 3天造了一个深度学习轮子,生猛!
- COLING 2020 | CharBERT:字符敏感的预训练语言模型
- 用少于10行代码训练前沿深度学习新药研发模型