说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. Undo 相关的等待事件和已知问题 (Doc ID 1575701.1)

    Undo Related Wait Events & Known Issues (Doc ID 1575701.1) APPLIES TO: Oracle Database - Enterpr ...

  2. [PHP] stream_set_blocking非阻塞模式影响fgets fread函数

    当设置socket为非阻塞时,fread或者fgets函数会立即返回结果,而不需要等待有输入,测试过程可以使用vscode的debug模式来进行当不设置这一项时,如果客户端没有输入会一直阻塞在这里等待 ...

  3. Where does Oracle SQL Developer store connections? oracle SQL Developer 连接信息保存的位置,什么地方

    oracle SQL Developer 连接信息保存的位置,在什么地方? 在切换登录用户后,oracle SQL Developer 连接信息不见了.只要以前的用户信息还存在,可以在路径 C:\Us ...

  4. 在Windows系统中安装matplotlib,需要注意的问题

    matplotlib的下载地址:https://pypi.org/project/matplotlib/#files 以python3.6为例,适合的版本matplotlib-3.1.1-cp36-c ...

  5. OpenDaylight开发hello-world项目之代码框架搭建

    OpenDaylight开发hello-world项目之开发环境搭建 OpenDaylight开发hello-world项目之开发工具安装 OpenDaylight开发hello-world项目之代码 ...

  6. Linux war包部署jenkins

    一.介绍Jenkins 1.Jenkins概念 Jenkins是一个功能强大的应用程序,允许持续集成和持续交付项目,无论用的是什么平台.这是一个免费的源代码,可以处理任何类型的构建或持续集成.集成Je ...

  7. 重磅来袭!Reactive 架构专场四城巡回演讲

    Reactive 究竟是什么?Reactive 对架构设计的影响和冲击,以及给开发方式带来的改变有哪些?为什么阿里巴巴.Pivotal.Facebook 纷纷在生产环境中实践 Reactive? 本次 ...

  8. RabbitMQ的交换器Exchange之direct(发布与订阅 完全匹配)

    1.交换器.用来接收生产者发送的消息并将这些消息路由给服务器中的队列.三种常用的交换器类型,a.direct(发布与订阅 完全匹配).b.fanout(广播).c.topic(主题,规则匹配). 2. ...

  9. EF中获取当前上下文的表名

    EF在处理并发上并不是很好,很多时候我们需要手动写sql操作数据库.但是在基类中我们如何获取当前服务仓储操作的表呢? 使用正则是其中一种解决办法 Repository.Table是一条查询语句,通过t ...

  10. python基础(11):函数(一)

    1. 什么是函数 1.我们到⽬前为⽌,已经可以完成⼀些软件的基础功能了.那么我们来完成这样⼀个功能: 约会: print("拿出⼿机") print("打开陌陌" ...