说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. RDIFramework.NET敏捷开发框架Web新增邮件中心实现便捷式的邮件收发

    1.引言 邮件收发在很多业务系统中都有这样的需求,是比较正式和常用的功能.在我们的框架中提供了邮件中心功能模块,集内部邮件的收发.邮件归类.邮件星标的标记.邮件的删除与彻底删除等,邮件中心功能模块界面 ...

  2. Android Studio添加文件注释头模板集合

    Android Studio中设置方式 File -> Settings -> Editor -> File and Code Templates -> 右侧File标签 -& ...

  3. 用了这么久HTTP, 你是否了解Content-Length?

    摘要: 理解HTTP协议... 原文:用了这么久HTTP, 你是否了解Content-Length和Transfer-Encoding ? 作者:朴瑞卿的博客 由Content-Length导致的问题 ...

  4. MySQL 数据库查询数据,过滤重复数据保留一条数据---(MySQL中的row_number变相实现方法)

    转自: http://www.maomao365.com/?p=10564 摘要: 下文讲述MySQL数据库查询重复数据时,只保留一条数据的方法 实现思路: 在MySQL数据库中没有row_numbe ...

  5. docker 无法启动

    背景:想修改docker0的ip地址,所以在/etc/docker/daemon.json文件里加了[bip]. { "registry-mirrors": ["http ...

  6. Python:判断列表中含有字符串且组成新的列表打印输出-Dotest董浩

    '''题一:判断列表中含有字符串且组成新的列表打印输出知识点:列表.列表的增删改查.for循环.if判断'''#@Author:Dotest软件测试#@QQ:1274057839names = ['D ...

  7. SSL握手中win xp和SNI的那点事

    SSL握手中win xp和SNI的那点事 一.背景需求server1-3使用不同的域名对外提供https服务,用nginx作为前端负载均衡器并负责https集中解密工作(以用户访问的域名为依据进行流量 ...

  8. P4728 [HNOI2009]双递增序列

    题意 这个DP状态有点神. 首先考虑一个最暴力的状态:\(f_{i,j,k,u}\)表示第一个选了\(i\)个,第二个选了\(j\)个,第一个结尾为\(k\),第二个结尾为\(u\)是否可行. 现在考 ...

  9. electron内监控目标网站cookie的变化,查找指定的cookie

    let cookieInstance = win.webContents.session.cookies; cookieInstance.on('changed', (e, cookie, cause ...

  10. Global Azure Bootcamp 2019 宁波站活动总结

    4月27日,由微软MVP技术社区发起的Global Azure Bootcamp 2019盛会在全球80多个国家270个城市举办.本次活动由全国众多Azure专家及微软MVP技术社区成员,分别在北京. ...