LinkedHashMap源码和实现LRU算法

LRU算法(有彩蛋) 文章目录1.背景2.LRU详解2.1 什么是LRU?2.2 LRU算法设计2.3 新增&修改2.4 访问2.5 删除3.LRU实现3.1 Java自己封装实现3.2 基于LinkedHashMap实现4.彩蛋4.1 FIFO算法及实现4.2 LFU算法及实现4.3 HashMap数据结构及源码解析 1.背景 我们在各类缓存等应用场景中都涉及到LRU算法。接下来我仔细分析一下LRU算法的设计... 阅读详情

LinkedHashMap特别有意思,它不仅仅是在HashMap上增加Entry的双向链接,它更能借助此特性实现保证Iterator迭代按照插入顺序(以insert模式创建LinkedHashMap)或者实现LRU(Least Recently Used最近最少算法,以access模式创建LinkedHashMap)。

下面是LinkedHashMap的get方法的代码

public V get(Object key) {
        Entry<K,V> e = (Entry<K,V>)getEntry(key);
        if (e == null)
            return null;
        e.recordAccess(this);
        return e.value;
    }

其中有一段:e.recordAccess(this)。下面我们进入Entry的定义

void recordAccess(HashMap<K,V> m) {
            LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
            if (lm.accessOrder) {
                lm.modCount++;
                remove();
                addBefore(lm.header);
            }
        }

这里的addBefore(lm.header)是做什么呢?再看

private void addBefore(Entry<K,V> existingEntry) {
            after  = existingEntry;
            before = existingEntry.before;
            before.after = this;
            after.before = this;
        }

从这里可以看到了,addBefore(lm.header)是把当前访问的元素挪到head的前面,即最近访问的元素被放到了链表头,如此要实现LRU算法只需要从链表末尾往前删除就可以了,多么巧妙的方法。

在看到LinkedHashMap之前,我以为实现LRU算法是在每个元素内部维护一个计数器,访问一次自增一次,计数器最小的会被移除。但是要想到,每次add的时候都需要做这么一次遍历循环,并取出最小的抛弃,在HashMap较大的时候效率很差。当然也有其他方法来改进,比如建立<访问次数,LinkedHashMap元素的key>这样的TreeMap,在add的时候往TreeMap里也插入一份,删除的时候取最小的即可,改进了效率但没有LinkedHashMap内部的默认实现来的简捷。

LinkedHashMap是什么时候删除的呢?

 void addEntry(int hash, K key, V value, int bucketIndex) {
        super.addEntry(hash, key, value, bucketIndex);
        // Remove eldest entry if instructed
        Entry<K,V> eldest = header.after;
        if (removeEldestEntry(eldest)) {
            removeEntryForKey(eldest.key);
        }
    }

在增加Entry的时候,通过removeEldestEntry(eldest)判断是否需要删除最老的Entry,如果需要则remove。注意看这里Entry<K,V> eldest=header.after,记得我们前面提过LinkedHashMap还维护一个双向链表,这里的header.after就是链表尾部最后一个元素(头部元素是head.before)。
LinkedHashMap默认的removeEldestEntry方法如下

protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return false;
    }

总是返回false,所以开发者需要实现LRU算法只需要继承LinkedHashMap并重写removeEldestEntry方法,下面以MyBatis的LRU算法的实现举例
keyMap = new LinkedHashMap<Object, Object>(size, .75F, true) {
private static final long serialVersionUID = 4267176411845948333L;

  protected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {
    boolean tooBig = size() > size;
    if (tooBig) {
      eldestKey = eldest.getKey();
    }
    return tooBig;
  }
};

开发者的子类并不需要直接操作eldest(上例中获得eldestKey只是MyBatis需要映射到Cache对象中的元素),只要根据自己的条件(一般是元素个数是否到达阈值)返回true/false即可。注意,要按照LRU排序必须在new LinkedHashMap()的构造函数的最后一个参数传入true(true代表LinkedHashMap内部的双向链表按访问顺序排序,false代表按插入顺序排序)。

在LinkedHashMap的注释里明确提到,该类在保持插入顺序、不想HashMap那样混乱的情况下,又没有像TreeMap那样的性能损耗。同时又能够很巧妙地实现LRU算法。其他方面和HashMap功能一致。有兴趣的同学可以仔细看看LinkedHashMap的实现。

LinkedHashMap实现LRU;具体实现如下:只需要重写removeEldestEntry方法即可


 
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
 
public class LRULinkedMap<K, V> {
 
	/**
     * 最大缓存大小
     */
	private int cacheSize;
	
	private LinkedHashMap<K, V> cacheMap;
	
	public LRULinkedMap(int cacheSize){
		this.cacheSize = cacheSize;
		
		cacheMap = new LinkedHashMap(cacheSize, 0.75F, true){
 
			@Override
			protected boolean removeEldestEntry(Entry eldest) {
					return cacheSize + 1 >= cacheMap.size();
			}
		};
	}
	
	public void put(K key, V value){
		cacheMap.put(key, value);
	}
	
	public V get(K key){
		return cacheMap.get(key);
	}
	
	public Collection<Map.Entry<K, V>> getAll(){
		return new ArrayList<Map.Entry<K, V>>(cacheMap.entrySet());
	}
	
	public static void main(String[] args) {
		LRULinkedMap<String, Integer> map = new LRULinkedMap<>(3);
		map.put("key1", 1);
		map.put("key2", 2);
		map.put("key3", 3);
		
		for (Map.Entry<String, Integer> e : map.getAll()){
			System.out.println(e.getKey()+"====>"+e.getValue());
		}
		System.out.println("\n");
		map.put("key4", 4);
		for (Map.Entry<String, Integer> e : map.getAll()){
			System.out.println(e.getKey()+"====>"+e.getValue());
		}
		
	}
	 
}

原文转自
https://www.cnblogs.com/mengheng/p/3683137.html

在这里插入图片描述

Opencv计算相机响应函数(Camera Response Function)与Radiance 本文主要用于记录自己在学习CRF过程中遇到的一些问题。 CRF模型 I=f(V(t⋅L))I=f(V( t\cdot L))I=f(V(t⋅L)) 其中III为相机灰度值Intensity,LLL为环境中irradiance,ttt为曝光时间,VVV为相机镜头参数,fff为相机响应函数CRF。 有些论文中认为相机镜头参数是线性的不考虑,但有些考虑了衰减即靠近图像边缘亮度会暗一些,但没有看到二者同时计算的,如果同时计算两个非线性的函数,我觉得可能会有不确定性,在这里还请教一下了解的朋友。 控制 阅读详情

相关推荐

SVG文件上传漏洞实战:从XSS攻击到防御策略

本文深入剖析了SVG文件上传漏洞的成因与危害,揭示了攻击者如何利用SVG的XML本质构造恶意文件,绕过常规检查实现存储型XSS攻击。文章通过实战复现演示了完整的攻击链,并提供了从严格内容检查、安全解析过滤到设置CSP策略等多层次的纵深防御方案,帮助开发者从根本上加固文件上传功能。

weixin_29230805的博客 395

LinkedHashMap实现LRU

前言: LinkedHashMap是HashMap的子类,在原有HashMap数据结构的基础上,它还维护着一个双向链表链接所有entry,这个链表定义了迭代顺序,通常是数据插入的顺序。 上图我只画了链表,其实红黑树节点也是一样的,只是节点类型不一样而已 也就是说我们遍历LinkedHashMap的时候,是从head指针指向的节点开始遍历,一直到tail指向的节点。 源码 public class LinkedHashMap<K,V> extends HashMap<K,V> imp

张井天的博客 2469

实战分享:如何用Java调用Doris FE接口实现高效Stream Load数据导入(附完整代码)

本文详细介绍了如何通过Java调用Doris FE接口实现高效的Stream Load数据导入,包含完整代码示例和性能优化技巧。Stream Load作为Doris的高效数据导入方式,相比传统JDBC提升5-10倍速度,适用于大规模数据处理场景,帮助开发者解决高吞吐量数据导入挑战。

weixin_29304985的博客 417

使用LinkedHashMap实现LRU算法

LRU算法,最近最少使用原则,如果要实现该算法,可以借助LinkedHashMap数据结构,LinkedHashMap继承HashMap,底层使用哈希表和双向链表来保存所有元素,使用LinkedHashMap可以确保元素按照顺序进行存储。 默认情况下,LinkedHashMap是按照元素的添加顺序存储,也可以启用按照访问顺序存储,即最近读取的数据放在最前面,最早读取的数据放在最后面,然后它还有一个判断是否删除最老数据的方法,默认是返回false,即不删除数据。 下面就基于这两种存储方式,简单展示一下如何

张维鹏的博客 8172

EtherCAT应用层协议选型指南:CoE、SoE、EoE、FoE、AoE到底怎么选?看完这篇就懂了

本文深入解析EtherCAT应用层协议(CoE、SoE、EoE、FoE、AoE)的选型策略,从实时性、数据吞吐量和功能完整性三大核心指标出发,提供工业场景下的实战决策框架。通过技术特性对比、混合协议架构设计和常见故障规避指南,帮助工程师优化自动化设备通信性能。

weixin_28718793的博客 487

YOLO26-seg分割优化:轻量化卷积魔改 | 新的partial convolution(PConv)结合C3k2 | CVPR2023

​​​​​摘要:本研究对Ultralytics YOLO26进行了全面分析,重点阐述了其关键架构改进及其在实时边缘目标检测中的性能基准测试。YOLO26于2025年9月发布,是YOLO系列最新、最先进的成员,专为在边缘及低功耗设备上实现高效、精确且易于部署的目标而构建。本文依次详述了YOLO26的架构创新,包括:移除了分布焦点损失(DFL);采用端到端的无NMS推理;集成了渐进损失(ProgLoss)与小目标感知标签分配(STAL);以及引入了用于稳定收敛的MuSGD优化器。

①答疑群聊服务;②YOLO大模型知识问答系统;③计算机视觉论文生成智能体; 149

LinkedHashMap实现LRU算法

LinkedHashMap特别有意思,它不仅仅是在HashMap上增加Entry的双向链接,它更能借助此特性实现保证Iterator迭代按照插入顺序(以insert模式创建LinkedHashMap)或者实现LRU(Least Recently Used最近最少算法,以access模式创建LinkedHashMap)。 下面是LinkedHashMap的get方法的代码 public V ...

weixin_30892037的博客 188

【数据集处理】中国地面气候资料日值数据集(V3.0)(含MATLAB全代码)

简介数据集数据处理

WW、forever的博客 1万+

LinkedHashMap

一、基础概念 下图很好地还原了LinkedHashMap的原貌:HashMap和双向链表的密切配合和分工合作造就了LinkedHashMap。特别需要注意的是,next用于维护HashMap各个桶中的Entry链,before、after用于维护LinkedHashMap的双向链表,虽然它们的作用对象都是Entry,但是各自分离,是两码事儿。 LinkedHashMap的继承结构如图: HashMap与LinkedHashMap的Entry结构示意图如下图所示 1.遍历 LinkedHashMap进行

sinat_34814635的博客 603

ccSwitch 安装使用指南,claude code的最佳搭档

ccSwitch 是一款真正为 AI 编程开发者打造的效率工具。它把原本繁琐的配置管理工作,简化成了直观的图形界面操作。无论你是需要在多个 API 提供商之间切换,还是想要统一管理多款 AI 编程工具,ccSwitch 都能帮你大幅提升效率。如果你是重度 AI 编程工具用户,强烈推荐尝试一下 ccSwitch,相信它会成为你开发工具箱中不可或缺的一员。项目地址。

篮球界最会写bug的人;程序猿中打球最菜的人。 1282

基于Simulink的电动汽车动力总成控制策略验证与标定仿真平台

电动汽车的动力总成(Powertrain)是车辆的核心系统,包括动力电池、电机控制器、逆变器和驱动电机等关键部件。动力总成的控制策略直接影响车辆的动力性能、能耗效率和驾驶体验。为了验证和优化这些控制策略,基于MATLAB/Simulink的仿真平台成为一种高效且经济的解决方案。本项目旨在构建一个完整的基于Simulink的电动汽车动力总成控制策略验证与标定仿真平台,涵盖控制策略建模、性能评估以及参数标定等功能模块,并通过仿真验证系统的有效性。

xiaoheshang_123的博客 177

使用LinkedHashMap实现固定大小的LRU缓存

使用LinkedHashMap实现固定大小的LRU缓存

shyの个人笔记 2367

手撕Lua字节码:从黑盒到透明

lua 字节码 怎么‘手撕’一个 chunk 看看里面啥样?我手里有一个.luac或出来的二进制字节码,想知道里面到底是什么结构、哪些字段、有哪些指令,怎么一步一步“拆箱”,从一个黑盒变成有迹可循的东西?也就是:不满足于只会loadpcall而是想亲眼看看一个 chunk 内部长啥样,甚至写点工具把它解析出来。这篇就用带你从“拿到一坨.luac不搞高深玄学,尽量让你看完就能自己动手。注:以 Lua 5.3/5.4 为主,细节各版本略有不同,但大体套路是一致的。

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 97

Java集合:浅谈LinkedHashMap、LinkedHashSet源码及LRU算法实现

Java集合:浅谈LinkedHashMap、LinkedHashSet源码及LRU算法实现

qq_41490913的博客 369

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

基于源码搞懂LinkedHashMap并通过其实现LRU算法

LinkedHashMap 是通过哈希表和双向链表来实现的,其基于双向链表来保证对哈希表迭代时的有序性。 LinkedHashMap 继承自 HashMap,从而可以直接复用 HashMap 对哈希表的操作逻辑,其只需要额外维护1套双向链表的操作逻辑即可。 public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> { ...... } 节点 LinkedHashMa

打酱油的葫芦娃 3805

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

linkedhashmap遍历_Java集合:浅谈LinkedHashMap、LinkedHashSet源码及LRU算法实现

Java的HashSet、HashMap集合应用及底层原理,相信大家都已经很熟悉了,这里就不再赘述了。这里主要来介绍下如何Java中的LinkedHashMap集合,同时也介绍下基于LinkedHashMap的LinkedHashSet集合、LRU算法实现LinkedHashMap插入顺序遍历LinkedHashMap集合是基于HashMap实现的,所以它具有HashMap的特性。但是我们在使用H...

weixin_39780962的博客 1170

LinkedHashMap源码分析及实现LRU算法

PS: 要先了解HashMap的实现原理HashMap源码分析 一、简单介绍 public class LinkedHashMap&amp;amp;amp;amp;lt;K,V&amp;amp;amp;amp;gt; extends HashMap&amp;amp;amp;amp;lt;K,V&amp;amp;amp;amp;gt; implements Map&amp;amp;amp;amp;lt;K,V&amp;amp;amp;amp;gt;

seasonLai的博客 310

剖析LRU算法及LinkedHashMap源码实现机制

一、简述 LRU(Least Recently Used),注意L代表的不是Latest,翻译成中文通常叫:近期最少使用算法、最近最少使用算法。LRU与LFU(Least Frequently Used)、FIFO(First In First Out)是3种常用的缓存算法(页面置换算法)。缓存算法的应用场景有很多,例如操作系统在物理内存不足时触发的磁盘交换、CPU中L1、L2、L3缓存淘汰

Logica的专栏 2200

如何使用 LinkedHashMap 实现 LRU 缓存?

缓存是提高数据读取性能的通用技术,在硬件和软件设计中被广泛使用,例如CPU 缓存、Glide 内存缓存,数据库缓存等。由于缓存空间不可能无限大,当缓存容量占满时,就需要利用某种策略将部分数据换出缓存,这就是缓存的替换策略 / 淘汰问题。使用一个随机数生成器随机地选择要被淘汰的数据块;记录各个数据块的访问时间,最早访问的数据最先被淘汰;记录各个数据块的访问“时间戳”,最近最久未使用的数据最先被淘汰。

java_beautiful的博客 893

深入理解LinkedHashMap和LRU缓存

LinkedHashMap 概述 HashMap 是 Java Collection Framework 的重要成员,也是Map族中我们最为常用的一种。不过遗憾的是,HashMap是无序的,也就是说,迭代HashMap所得到的元素顺序并不是它们最初放置到HashMap的顺序。 HashMap的这一缺点往往会造成诸多不便,因为在有些场景中,我们确需要用到一个可以保持插入顺序的Map。庆幸的是,JDK为我们解决了这个问题,它为HashMap提供了一个子类 —— LinkedHashMap。虽然LinkedHas

qq_40959750的博客 453

java lru lfu_Java集合之LinkedHashMap实现LRU,LFU,FIFO算法

LinkedHashMap=双向链表+HashMap,存储相比HashMap会多了一个前节点,后节点.LinkedHashMap简介LinkedHashMap主要是通过HashMap+双向链表来实现的,主要作用目前就个人使用来看,可以主要有插入排序,访问排序.有了这两个排序就可以很简单的实现LRU,FIFO缓存算法.至于怎么用,就看个人的改造能力了.下面将会分析源码,以及用它来实现各种缓存算法.L...

weixin_31677427的博客 623

【Java集合源码剖析】LinkedHashmap源码剖析

转载请注明出处:http://blog.youkuaiyun.com/ns_code/article/details/37867985 前言:有网友建议分析下LinkedHashMap的源码,于是花了一晚上时间研究了下,分享出此文(这个系列的最后一篇博文了),希望大家相互学习。LinkedHashMap的源码理解起来也不难(当然,要建立在对HashMap源码有较好理解的基础上)。 L...

weixin_30493321的博客 88

彻底理解HashMap及LinkedHashMap

HashMap是Map族中最为常用的一种,也是 Java Collection Framework 的重要成员。HashMap和双向链表合二为一即是LinkedHashMap。所谓LinkedHashMap,其落脚点在HashMap,因此更准确地说,它是一个将所有Node节点链入一个双向链表的HashMap。ConcurrentHashMap是java.util.concurrent包的重要成员,...

Hopefully Sky的博客 5468

Java集合 - LinkedHashMap

Java集合 - LinkedHashMap

qq_43350524的博客 979

Java中LinkedHashMap底层实现

目录 序言: 1:LinkedHashMap中的put(key,value) 1.1:LinkedHashMap中对putVal()方法源码描述: 1.2:LinkedHashMap中对节点操作方法源码描述: 1.3:LinkedHashMap中afterNodeAcces()方法源码描述: 1.4:LinkedHashMap中afterNodeInsertion()方法源码描述: ...

F_Hello_World的博客 635

Java 集合 - LinkedHashMap 解析

一、前言 上一篇《Java 集合 - HashMap 解析》我们学习了 HashMap,HashMap 是无序的,当我们希望有顺序地去存储 key-value 时,就需要使用 LinkedHashMap 了。LRU 算法就是利用 LinkedHashMap 的有序性。下面我们来学习一下 LinkedHashMap。 二、源码解析 我们先看一下 LinkEdHashMap 的数据结构图:...

lerendan的博客 508
上一篇: Apache Curator客户端的使用
下一篇: 架构技术栈
牧竹子
博客等级 码龄17年 572粉丝 233原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值