说LinkHashMap之前,我们先来谈谈什么是LRU算法?

按照英文的直接原义就是Least Recently Used,最近最久未使用法,它是按照一个非常注明的计算机操作系统基础理论得来的:最近使用的页面数据会在未来一段时期内仍然被使用,已经很久没有使用的页面很有可能在未来较长的一段时间内仍然不会被使用。基于这个思想,会存在一种缓存淘汰机制,每次从内存中找到最久未使用的数据然后置换出来,从而存入新的数据!它的主要衡量指标是使用的时间,附加指标是使用的次数。在计算机中大量使用了这个机制,它的合理性在于优先筛选热点数据,所谓热点数据,就是最近最多使用的数据!因为,利用LRU我们可以解决很多实际开发中的问题,并且很符合业务场景。

双向循环链表

public class LinkedHashMap<K,V>extends HashMap<K,V>{
transient LinkedEntry<k,V> header; //头结点
private final boolean accessOrder; //true:访问排序 false:插入排序 public LinkedHashMap(){
  init();
  accessOrder=false; //默认情况为false,基于插入排序的
}
static class LinkedEntrykK,V> extends HashMapEntry<K, V>     //linkedEntry继承了HashMapEntry,也就拥有了父类的所有属性和方法

{
LinkedEntry<K, V> nxt;
LinkedEntry<K, V> prv; static class HashMapEntry<K, V> implements Entry<K, V> {
final K key;
V value;
final int hash;
HashMapEntry<K, V> next; HashMapEntry(K key, V value, int hash, HashMapEntry<k, V> next) {
this.key = key;
this.value = value;
this.hash = hash;
this.next = next;
}

linkedHashMap只是重写了hashMap put方法里的addNewEntry增加新元素方法

header:头结点

eldest:最先进来的结点(最老的)

oldTail:

newTail:新添加的结点

table[index]:一维数组,把新的尾巴加入到table[index]里面来

@Override
void addNewEntry(K key, V value, int hash, int index) {
LinkedEntry<K, V> header = this.header; LinkedEntry<K, V> eldest = header.nxt; if (eldest != header && removeEldestEntry(eldest)) {如果头结点不是自己抱自己
remove(eldest.key);
}
LinkedEntry<K, V> oldTail = header.prv;
  //添加一个新元素
LinkedEntry<K, V> newTail = new LinkedEntry<K, V>(
key, value, hash, table[index], header(next), oldTail(previous)); //做构造函数时newTail.next指向header
①table[index] = ②oldTail.nxt = ③header.prv = ④newTail; 4=3 4=2 2=1
}

因为新加进来的元素是在队尾插入的,不断插入元素的话就不断移动,如果eldest没有用了,将来就用removeEldestEntry方法移除

//默认构造方法,头结点自己指向自己,也就是自己抱自己
@Override void init(){
header]=new uinkedEntry<K,V>(); LinkedEntry(){
super(nu11,nul1,0,null); nxt = prv = this;

隐藏了一列一维数组,将来还是有用的

默认return false;不会移除     方法的作用:是在内存过高时,移除最老的元素,所以需要重写这个方法,return true;
protected boolean removeEldestEntry(Map. Entry<k,V>eldest){
  return false;
}

访问

如果要访问 包含头结点顺时针第四个元素,让它成为最新的,就需要把第五个和第三个结点连起来,再在队尾用addNewEntry方法添加一个newTail

e:访问到的元素

@Override
public V get(Object key) {
if (key == null) {
HashMapEntry<k, V> e = entryForNullKey;
if (e == null)
return null;
if (accessOrder)
makeTai1((LinkedEntry<K, V>) e);
return e.value;
int hash = Collections.secondaryHash(key);
HashMapEntry<K, V>[] tab = table;
for (HashMapEntry<k, V> e = tab[hash & (tab.length - 1)];
e != null; e = e.next) {
K eKeyI = e.key;
if (ekey == key Il(e.hash == hash && key.equals(ekey))){ //如果找到了这个元素
if (accessOrder)
makeTail((LinkedEntry<K, V>) e); //将访问到的元素当做尾巴反正队尾添加进来
return e.value;
}
}
return null;
}
private void makeTail(LinkedEntry<k, V> e) {
e.prv.nxt = e.nxt; //e.prv(a).nxt=e.nxt(oldTail)
e.nxt.prv = e.prv;
LinkedEntry<K, V> header = this.header;
LinkedEntryf, V > oldTail = header.prv;
e.nxt = header;
e.prv = oldTail;
o1dTail.nxt = header.prv = e;
modCount++;
}

新进来的要放在队头

最后进来的是最新的

顺序存储,谁先存进来的,谁先被移出去。

访问排序,谁最近被访问就是最活跃的,最后才被移出去

LInkHashMap源码分析的更多相关文章

  1. spark-streaming-kafka-0-10源码分析

    转发请注明原创地址http://www.cnblogs.com/dongxiao-yang/p/7767621.html 本文所研究的spark-streaming代码版本为2.3.0-SNAPSHO ...

  2. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  3. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  4. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  5. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  6. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  7. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  8. java使用websocket,并且获取HttpSession,源码分析

    转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...

  9. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

随机推荐

  1. netperf 网络测试工具

    软件介绍: netperf是惠普公司开源的一款针对网络性能的测试工具,主要基于TCP或UDP的传输.根据应用的不同,可以进行批量数据传输(bulk data transfer)模式和请求/应答(req ...

  2. Python—创建进程的三种方式

    方式一:os.fork() 子进程是从os.fork得到的值,然后赋值开始执行的.即子进程不执行os.fork,从得到的值开始执行. 父进程中fork之前的内容子进程同样会复制,但父子进程空间独立,f ...

  3. Scrapy安装和简单使用

    模块安装 Windows 安装scrapy 需要安装依赖环境twisted,twisted又需要安装C++的依赖环境 pip install scrapy  时 如果出现twisted错误 在http ...

  4. FreeRTOS操作系统,在按键中断函数中恢复被挂起的任务,程序卡死的原因和解决办法

    出现问题场景:       作为刚接触FreeRTOS实时操作系统的菜鸟,我在练习一个程序功能:按键3按下,将LED闪烁的任务挂起:按键4按下,将LED闪烁的任务恢复到就绪.按键使用外部中断.恢复就绪 ...

  5. IDEA 第三方jar包 使用

    1,加入lib包中,在pom中添加 <dependency> <groupId>com.sss</groupId> <artifactId>包名< ...

  6. June 16th, 2019. Week 25th, Sunday.

    I can fly higher than an eagle, for you are the wind beneath my wings. 我之所以能飞得比鹰还高,是因为有你做我羽翼下的风. You ...

  7. 【LOJ6397】「THUPC2018」蛋糕 / Cake(搜索)

    点此看题面 大致题意: 把一个\(a\times b\times c\times d\)的\(4\)维图形划分成\(a\times b\times c\times d\)个小块,求有\(0\sim8\ ...

  8. Java中Set与Set<?>到底区别在哪?

    您可能知道,无界通配符 Set<?> 可以容纳任何类型的元素,而原始类型Set也可以容纳任何类型的元素.那它们之间有什么区别呢? 1.关于Set<?>的两个事实 关于Set&l ...

  9. 划词标注1——使用svg绘制换行文本并自动识别库中字典数据

    业务需求 给出一段文本,自动识别出文本中包含的关键字信息,关键字是库里已知的数据,根据类型的不同显示出不同的颜色 业务分析 1)采用css:文本识别出来后,根据识别出的文本更改对应文本的dom,通过更 ...

  10. 栈与后缀表达式C实现

    #include<stdio.h> #include<stdlib.h> typedef char datatype; typedef struct stack { int t ...