什么是LRU(最近最少使用)算法?

article/2025/9/29 18:09:27

一、什么是LRU?

          LRU(Least Recently Used),最近最少使用。

          是一种【内存管理】算法。

     LRU算法基于一种假设:

        长期不被使用的数据,在未来被用到的几率也不大。因此,当数据所占内存达到一定阈值时,要移除掉最近最少使用的数据。

   LRU算法使用了一种有趣的数据结构,叫做【哈希链表

 

二、什么是【哈希链表】呢?

       1)【哈希表】是由若干个【Key-Value】所组成的。

               在“逻辑”上,这些Key-Value是无所谓排列顺序的,谁先谁后都一样。

                

      2)  【哈希链表】当中,这些【Key-Value】不再是彼此无关的存在,而是被一个链条串起来了。

                每一个Key-Value都具有它的前驱Key-Value、后继Key-Value,就像双向链表中的节点一样。

                

  这样一来,原本无序的哈希表拥有了固定的排列顺序。

 

三、哈希链表和LRU算法有什么关系呢?

          1、依靠哈希链表的【有序性】,可以把Key-Value按照【最后的使用时间】来【排序】

              让我们以用户信息的需求为例,来演示一下LRU算法的基本思路:

              1.假设我们使用哈希链表来缓存用户信息,目前缓存了4个用户,这4个用户是按照时间顺序依次从链表右端插入的。

                 

              2.此时,业务方访问用户5,由于哈希链表中没有用户5的数据,我们从数据库中读取出来,插入到缓存当中。

                 这时候,链表中最右端是最新访问到的用户5,最左端是最近最少访问的用户1。

                 

               3.接下来,业务方访问用户2,哈希链表中存在用户2的数据,我们怎么做呢?

                  我们把用户2从它的前驱节点和后继节点之间移除,重新插入到链表最右端。

                  这时候,链表中最右端变成了最新访问到的用户2,最左端仍然是最近最少访问的用户1。

                 

               4. 接下来,业务方请求修改用户4的信息。

                   同样道理,我们把用户4从原来的位置移动到链表最右侧,并把用户信息的值更新。

                   这时候,链表中最右端是最新访问到的用户4,最左端仍然是最近最少访问的用户1。

                   

                 5  后来业务方换口味了,访问用户6,用户6在缓存里没有,需要插入到哈希链表。

                     假设这时候缓存容量已经达到上限,必须先删除最近最少访问的数据,那么位于哈希链表最左端的用户1就会被删除掉,然后再把用户6插入到                      最右端。

                   

         以上,就是LRU算法的基本思路。

    2、Java中的LinkedHashMap已经对【哈希链表】做了很好的实现。

         例如:

           

  1. private Node head;

  2. private Node end;

  3. //缓存存储上限

  4. private int limit;

  5.  

  6.  

  7. private HashMap<String, Node> hashMap;

  8.  

  9.  

  10. public LRUCache(int limit) {

  11.    this.limit = limit;

  12.    hashMap = new HashMap<String, Node>();

  13. }

  14.  

  15.  

  16. public String get(String key) {

  17.    Node node = hashMap.get(key);

  18.    if (node == null){

  19.        return null;

  20.    }

  21.    refreshNode(node);

  22.    return node.value;

  23. }

  24.  

  25.  

  26. public void put(String key, String value) {

  27.    Node node = hashMap.get(key);

  28.    if (node == null) {

  29.        //如果key不存在,插入key-value

  30.        if (hashMap.size() >= limit) {

  31.            String oldKey = removeNode(head);

  32.            hashMap.remove(oldKey);

  33.        }

  34.        node = new Node(key, value);

  35.        addNode(node);

  36.        hashMap.put(key, node);

  37.    }else {

  38.        //如果key存在,刷新key-value

  39.        node.value = value;

  40.        refreshNode(node);

  41.    }

  42. }

  43.  

  44.  

  45. public void remove(String key) {

  46.    Node node = hashMap.get(key);

  47.    removeNode(node);

  48.    hashMap.remove(key);

  49. }

  50.  

  51.  

  52. /**

  53. * 刷新被访问的节点位置

  54. * @param  node 被访问的节点

  55. */

  56. private void refreshNode(Node node) {

  57.    //如果访问的是尾节点,无需移动节点

  58.    if (node == end) {

  59.        return;

  60.    }

  61.    //移除节点

  62.    removeNode(node);

  63.    //重新插入节点

  64.    addNode(node);

  65. }

  66.  

  67.  

  68. /**

  69. * 删除节点

  70. * @param  node 要删除的节点

  71. */
     

  72. private String removeNode(Node node) {

  73.    if (node == end) {

  74.        //移除尾节点

  75.        end = end.pre;

  76.    }else if(node == head){

  77.        //移除头节点

  78.        head = head.next;

  79.    } else {

  80.        //移除中间节点

  81.        node.pre.next = node.next;

  82.        node.next.pre = node.pre;

  83.    }

  84.    return node.key;

  85. }

  86.  

  87.  

  88. /**

  89. * 尾部插入节点

  90. * @param  node 要插入的节点

  91. */

  92. private void addNode(Node node) {

  93.    if(end != null) {

  94.        end.next = node;

  95.        node.pre = end;

  96.        node.next = null;

  97.    }

  98.    end = node;

  99.    if(head == null){

  100.        head = node;

  101.    }

  102. }

  103.  

  104.  

  105. class Node {

  106.    Node(String key, String value){

  107.        this.key = key;

  108.        this.value = value;

  109.    }

  110.    public Node pre;

  111.    public Node next;

  112.    public String key;

  113.    public String value;

  114. }

  115.  

  116.  

  117. public static void main(String[] args) {

  118.    LRUCache lruCache = new LRUCache(5);

  119.    lruCache.put("001", "用户1信息");

  120.    lruCache.put("002", "用户1信息");

  121.    lruCache.put("003", "用户1信息");

  122.    lruCache.put("004", "用户1信息");

  123.    lruCache.put("005", "用户1信息");

  124.    lruCache.get("002");

  125.    lruCache.put("004", "用户2信息更新");

  126.    lruCache.put("006", "用户6信息");

  127.    System.out.println(lruCache.get("001"));

  128.    System.out.println(lruCache.get("006"));

  129. }

需要注意的是,这段不是线程安全的,要想做到线程安全,需要加上synchronized修饰符。

 

对于用户系统的需求,也可以使用【缓存数据库Redis】来实现,Redis底层也实现了类似于LRU的回收算法。


http://chatgpt.dhexx.cn/article/jOyOdgEu.shtml

相关文章

什么是LRU算法

什么是LRU LRU 英文全称&#xff08;Least recently used&#xff0c;最近最少使用&#xff09;属于典型的内存管理算法。 内存管理的一种页面置换算法&#xff0c;对于在内存中但又不用的数据块&#xff08;内存块&#xff09;叫做LRU&#xff0c;操作系统会根据哪些数据属于…

LRU缓存实现与原理

概念 LRU是 Least Recently Used 的缩写&#xff0c;即最近最少使用页面置换算法&#xff0c;是为虚拟页式存储管理服务的&#xff0c;是根据页面调入内存后的使用情况进行决策了。由于无法预测各页面将来的使用情况&#xff0c;只能利用“最近的过去”作为“最近的将来”的近似…

LRU算法的详细介绍与实现

1.背景 LRU&#xff08;least recently used-最近最少使用算法&#xff09;&#xff0c;是一种内存数据淘汰策略&#xff0c;使用常见是当内存不足时&#xff0c;需要淘汰最近最少使用的数据。LRU常用语缓存系统的淘汰策略。 2.LRU原理 LRU最早实在操作系统接触到这个算法的…

LRU原来如此简单

文章目录 前言一、LRU是什么&#xff1f;二、LFU是什么&#xff1f;三、LRU和LFU的比较四、LFU代码实现&#xff08;看懂LFU就自然懂了LRU了&#xff09;1、LFU类2、Node类3、测试 写在最后&#xff0c;感谢点赞关注收藏转发 前言 现在缓存技术在项目中随处可见&#xff0c;但…

LRU算法详解

概念理解 1.LRU是Least Recently Used的缩写&#xff0c;即最近最少使用页面置换算法&#xff0c;是为虚拟页式存储管理服务的&#xff0c;是根据页面调入内存后的使用情况进行决策了。由于无法预测各页面将来的使用情况&#xff0c;只能利用“最近的过去”作为“最近的将来”的…

LRU算法

1.什么是LRU算法 LRU算法又称最近最少使用算法&#xff0c;它的基本思想是长期不被使用的数据&#xff0c;在未来被用到的几率也不大&#xff0c;所以当新的数据进来时我们可以优先把这些数据替换掉。 在LRU算法中&#xff0c;使用了一种有趣的数据结构&#xff0c;称为哈希链…

巧用 NGINX 实现大规模分布式集群的高可用性

原文作者&#xff1a;陶辉 原文链接&#xff1a;巧用 NGINX 实现大规模分布式集群的高可用性 - NGINX开源社区 转载来源&#xff1a;NGINX开源社区 本文是我对2019年GOPS深圳站演讲的文字整理。这里我希望带给各位读者的是&#xff0c;如何站在整个互联网背景下系统化地理解Ngi…

朱邦复

朱邦复 求助编辑百科名片 朱邦复&#xff0c;仓颉输入法的发明人&#xff0c;现任香港上市公司文化传信集团的副主席。湖北省黄冈县人。为中文终端机、仓颉输入法、汉卡的发明人。由于其对中文电脑发展的众多贡献&#xff0c;台湾及香港地区的华人誉其为“中文电脑之父”、“中…

TCP/IP的底层队列实现原理

个人博客请访问 http://www.x0100.top 自从上次学习了TCP/IP的拥塞控制算法后&#xff0c;我越发想要更加深入的了解TCP/IP的一些底层原理&#xff0c;搜索了很多网络上的资料&#xff0c;看到了陶辉大神关于高性能网络编程的专栏&#xff0c;收益颇多。今天就总结一下&#…

从码农到工程师:看一下这6点!

作者&#xff1a;陶辉笔记来源&#xff1a;http://www.taohui.pub 许多程序员自称码农&#xff0c;因为每天事情总也做不完&#xff0c;而这些工作也没有给自己带来职业上的提升&#xff0c;总在原地打转&#xff0c;自己的工作似乎随时可被新人替换&#xff0c;可有可无。于是…

Nginx五大类变量详解

Nginx变量详解 文章目录 Nginx变量详解一、HTTP请求相关的变量二、TCP连接相关的变量三、Nginx处理请求过程中产生的变量四、发送HTTP响应时相关的变量五、Nginx系统变量 为了方便记忆呢&#xff0c;我把nginx的全部变量分为5种&#xff0c;详情见下图 本文内容取自极客时间陶辉…

开复博士见面会

CSDN的CTO俱乐部成立一年多来&#xff0c;做过很多次活动了。我只参加了两次&#xff0c;第二次就是开复博士的创新工厂介绍会。我对创新工厂兴趣并不大&#xff0c;但很想近距离接触一下这位声名远播的演讲者和布道者。 曾经和一个&#xff36;&#xff30;的会议上&#xff…

Nginx核心知识100讲学习笔记(陶辉)Nginx架构基础(一)

(转载&#xff0c;非常不错的文章) 一、Nginx的请求处理流程进程结构 1、Nginx的请求处理流程 2、Nginx的进程结构 3、进程作用 1、Master进程 1、是进行work进程的监控管理的2、看看work进程是否正常工作需不需要进行热部署、需不需要重新载入配置文件 2、Cache manager …

在这里,NGINX 创始人 Igor Sysoev 将亲述 NGINX 的诞生史

2020 年 5 月 20 日&#xff0c;一场 NGINX 在国内的盛会、一个所有 NGINX 用户 & 爱好者朝圣的最佳场所&#xff0c;F5 线上技术峰会 – NGINX 专场将以线上直播的形式面向所有开发者召开。届时各位 NGINX 开发者心目中的偶像 NGINX 创始人 Igor Sysoev 以及国内 NGINX 技…

如何用NGINX实现UDP四层反向代理?

原文作者&#xff1a;陶辉 原文链接&#xff1a;如何用NGINX实现UDP四层反向代理&#xff1f;- NGINX开源社区 转载来源&#xff1a;NGINX开源社区 在实时性要求较高的特殊场景下&#xff0c;简单的UDP协议仍然是我们的主要手段。 UDP协议没有重传机制&#xff0c;还适用于同时…

Nginx深度剖析,真是被大牛讲透了

开篇 Nginx是一款非常出色的服务器软件&#xff0c;从开始工作到现在&#xff0c;周围所有的公司都在使用Nginx。在多年的使用过程中&#xff0c;逐渐对Nginx的源码产生了浓厚的兴趣&#xff0c;我不满足于仅仅会使用&#xff0c;我想更加深入的理解它的内部工作原理。只有深入…

CPGIS三十周年专访系列|陶闯主席

近日&#xff0c;国际华人地理信息科学协会CPGIS建会30周年之际&#xff0c;开展了一次历届主席专访活动&#xff0c;陶闯博士作为国际华人地理信息科学协会CPGIS&#xff0c;2000-2001届的主席&#xff0c;接受了CPGIS的专访&#xff0c;忆往昔&#xff0c;看今朝&#xff0c;…

【10道大厂必考的计算机网络问题】陶辉老师

目录 1.请详细介绍一下TCP的三次握手协议,为什么要三次握手&#xff1f; 2.说说HTTP协议中缓存的处理流程&#xff1f;缓存的应用流程&#xff1f;与缓存相关的HTTP头部&#xff1f; 3.在地址栏键入URL后,网络世界发生了什么&#xff1f; 4.使用HTTP长连接有哪些优点&#…

HTTP详细介绍

转自&#xff1a;HTTP详细介绍本文参考 wiki百科、陶辉老师《Web协议详解与抓包实战》 和 作者在一线多年的运维工作总结希望对大家有所帮助。常见osi模型(7层)发起组织&#xff1a; 国际电信联盟电信标准化部门&#xff0c;与国际标准组织&#xff08;ISOhttps://www.pinlue.c…

10 道大厂面试必考的计算机网络问题-陶辉 极客时间

大厂中更多会考察你的长板. 在大厂中要学会求助 1.TCP的三次握手机制,为什么要三次? 为什么需要握手? 需要同步序列号,当然也有MSS(最大报文段长度),滑动窗口. 为什么是3次? 正常想法应该是: C:我要建连接,我的seq是这个; S:我收到了 S:我的Seq是这个 C:我也收到了…