热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

理解LinkedHashMap实现LRU缓存

工作里项目的代码有看到用hashmap做简单缓存的,一直没去细看,最近详细研究了这方面一下,发现好像这题还是面试的比较多的题,自己在这里做下总结。自己用go

       工作里项目的代码有看到用hashmap做简单缓存的,一直没去细看,最近详细研究了这方面一下,发现好像这题还是面试的比较多的题,自己在这里做下总结。

       自己用google搜中文结果,博客园里这篇博客是排第一的http://www.cnblogs.com/lzrabbit/p/3734850.html,算比较详实,但像文章里3楼评论说的那样,实现Map接口并不能保证获得线程安全,很好验证,可以自己用多线程编码模拟同时很多个客户端去访问容器。然后文章的另一个缺陷还是在于没有深入探究为什么要使用LinkedHashMap来实现LRU缓存。

        然后自己又搜索了英文解决方案,感觉结合文章1和文章2就可以深入理解为什么是使用LinkedHashMap来实现是最优最方便的方案。

        简单说下,文章1从三个层面来谈我们实现缓存的需求。

第一是缓存大小要有限度,不能无限的耗内存;

第二是查找操作尽可能快,最好是O(1);

第三是当缓存容量满了要选择Entry替换算法,在这里是LRU;

(Fixed size: The cache needs to have some bounds to limit memory usage.
    Fast access: The cache insert and lookup operations need to be fast preferably O(1) time.
    Entry replacement algorithm: When the cache is full, the less useful cache entries are purged from cache. The algorithm to replace these entries is Least Recently Used     (LRU) - or the cache entries which have not been accessed recently will be replaced.)

        接着讨论了用HashMap实现的不足,主要是HashMap可以接收一个初始的容量值,但当容器满了之后它会自动扩容,所以我们要实现LRU需要重写它的put方法然后在insert之前选择一条纪录remove。一个可行的方案是维护一个时间戳(timestamp),然后每次remove掉最老的一条纪录,但是搜索的代价是O(N)。

       所以我们需要维护一个排好序的列表,而排序的基础就是其中纪录条被访问的顺序。我们可以使用双端链表,当某条纪录被访问的时候,同时把这条纪录移到链表的尾部,然后当容器满了的时候我们移除链表头的那条纪录。如果采用的数据结构是ArrayList,那当我们移除一条纪录的时候其它的纪录都要被移动,而双端链表则没有这个问题。
至此,我们已经提出了一个insert和search都是O(1)代价的方案。

        幸运的是,JDK里原生的LinkedHashMap符合了我们的所有需求。实现的代码可参考博客园的文章。文章2里是用的HashMap加作者自己代码实现的简略版双端链表,可以让人更直观的理解为什么可以insert和search的代价都是O(1)。如果觉得双端队列代码比较难理解可以自己画画图,实现不行再推荐一个网站可以看到各种数据结构操作的动态过程,上一张截图


       上面可选数据结构,左下角选操作比方search、insert,右边是代码参考,下面的进度条还可以一步一步走,非常清晰。

       


推荐阅读
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了logistic回归(线性和非线性)相关的知识,包括线性logistic回归的代码和数据集的分布情况。希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了如何使用PHP向系统日历中添加事件的方法,通过使用PHP技术可以实现自动添加事件的功能,从而实现全局通知系统和迅速记录工具的自动化。同时还提到了系统exchange自带的日历具有同步感的特点,以及使用web技术实现自动添加事件的优势。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文详细介绍了相机防抖的设置方法和使用技巧,包括索尼防抖设置、VR和Stabilizer档位的选择、机身菜单设置等。同时解释了相机防抖的原理,包括电子防抖和光学防抖的区别,以及它们对画质细节的影响。此外,还提到了一些运动相机的防抖方法,如大疆的Osmo Action的Rock Steady技术。通过本文,你将更好地理解相机防抖的重要性和使用技巧,提高拍摄体验。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • Python SQLAlchemy库的使用方法详解
    本文详细介绍了Python中使用SQLAlchemy库的方法。首先对SQLAlchemy进行了简介,包括其定义、适用的数据库类型等。然后讨论了SQLAlchemy提供的两种主要使用模式,即SQL表达式语言和ORM。针对不同的需求,给出了选择哪种模式的建议。最后,介绍了连接数据库的方法,包括创建SQLAlchemy引擎和执行SQL语句的接口。 ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • 配置IPv4静态路由实现企业网内不同网段用户互访
    本文介绍了通过配置IPv4静态路由实现企业网内不同网段用户互访的方法。首先需要配置接口的链路层协议参数和IP地址,使相邻节点网络层可达。然后按照静态路由组网图的操作步骤,配置静态路由。这样任意两台主机之间都能够互通。 ... [详细]
  • This article discusses the efficiency of using char str[] and char *str and whether there is any reason to prefer one over the other. It explains the difference between the two and provides an example to illustrate their usage. ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 本文由编程笔记#小编整理,主要介绍了关于数论相关的知识,包括数论的算法和百度百科的链接。文章还介绍了欧几里得算法、辗转相除法、gcd、lcm和扩展欧几里得算法的使用方法。此外,文章还提到了数论在求解不定方程、模线性方程和乘法逆元方面的应用。摘要长度:184字。 ... [详细]
author-avatar
泉州联合网2534
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有