Java实现LRU算法

JAVA实现LRU算法 目录LRU算法LRU举例LRU题目思路分析代码实现 LRU算法 LRU是一种页面置换算法,least recently used(最近最少使用)算法,意思是在发生缺页现象时,需要置换页面的时候,将最近最少使用的页面删除,添加需要的页面进来 LRU举例 下面我们来看看具体的LRU算法是如何工作的,我们假设内存页面有2块,每次访问内存时总会一次性读取一页的数据进来,当页面数量不够时,发生LRU置换: 有以下页面走向:1 2 3 2 4 轮次 1 2 3 4 5 页面1 1 1 2 3 2 页 阅读详情

LRU算法

LRU(Least recently used)—最近最少被使用算法。在一些内存算法表现中若在一个内存有限的环境中,出现内存不足时为了保证程序的正常运行,会将一些价值较低的对象(如何来评定一个对象的价值的高低,对于LRU算法来说:如果数据最近被访问过,那么将来被访问的几率也更高,那么对应的价值就越高)进行清除,空出内存空间。

计算机操作系统基础理论中有一个经典理论:最近使用的页面数据会在未来一段时期内仍然被使用,已经很久没有使用的页面很有可能在未来较长的一段时间内仍然不会被使用。

2:LRU算法应用实现

在缓存应用中,使用LRU算法可以保证缓存数据量的可控,一旦缓存数据总量超过指定阀值,就将最近最少被访问的数据给清除掉。下面的具体的实现都基于cache需求来实现

2.1:Java中cache的实现(HashMap+双向链表实现)

实现思路:使用HashMap中value存储双向链表的各个节点,双向链表按照数据写入顺序的数据存储,一旦任意数据被访问,获取HashMap中该数据所在节点,将此节点移动到head(表示该数据最近被访问到),重新连接该节点上下节点。最终经常访问的数据会在双向链表前端聚齐,而不经常被访问的数据会聚集在链表尾部,一旦出现数据总量超过阀值时,我们可以通过将尾部的数据直接移除,来保证整个缓存的健康。

这里为何选用HashMap+双向链表来实现:

  1. HashMap的k,v结构对应这cache中k,v的概念,所以使用HashMap中V存储双向链表中的Node
  2. HashMap中查询写入的时间复杂度为O(1)
  3. 双向链表中的节点的移动,删除的时间复杂度为O(1)。
  4. 双向链表可以使我们通过任意一个节点获取其它所有节点

源码:

/**
 * 基于HashMap+双向链表
 * @author fangyuan
 */
public class MyLRUCache<K,V> {

    /**
     * 用于存储所有节点数据【利用HashMap中读写为O(1)特性】可以快速获取节点
     */
    private HashMap<K,Node<K,V>> nodes;

    /**
     * 用于存储双向链表头
     */
    private Node<K, V> head;

    /**
     * 用于存储双向链尾
     */
    private Node<K, V> tail;

    /**
     * 缓存中最大数据深度
     */
    private Integer maxSize;


    public MyLRUCache(Integer maxSize){

        if( ( maxSize =(maxSize ==null ? 16:maxSize))<6){

            throw new RuntimeException("缓存最大过小,最小值为6");
        }

        nodes = new HashMap<K,Node<K,V>>(maxSize,0.75F);

        this.maxSize = maxSize;

        //初始化
        this.head = null;
        this.tail = null;
    }

    /**
     * 定义双向链表结构
     */
    class Node<K, V> {

        private K key;

        private V value;

        private Node<K, V> before;

        private Node<K, V> after;

        public Node(K k,V v){
            this.key = k;
            this.value =v;
        }
    }

    public  void putCaceh(K k,V v){

        //创建数据节点
        Node<K,V> node = new Node<>(k,v);

        //将当前节点加入双向链表头
        this.addNewNode(node);
        //判断是否内存缓存超过最大深度

        if(nodes.size()>this.maxSize){
            //移除尾部数据
            removeTailNode();
        }
    }

    public Integer size(){
        return nodes.size();
    }

    
    private void removeTailNode() {

        this.tail.before.after = null;
        this.nodes.remove(tail.key);
        this.tail = tail.before;

    }

    private void addNewNode(Node<K,V> node) {

        if(nodes.containsKey(node.key)){

            //该key已经存在 替换值并
            Node cnode = nodes.get(node.key);

            cnode.value = node.value;

            afterNodeAccess(cnode);

        }else {
            //是一个新值只需要追加到双向链表头即可
            if(head != null){

                this.head.before = node;
                node.after = this.head;

                if(tail == null ){
                    tail = head;
                }
                this.head = node;

            }else {
                this.head = node;
                this.tail = this.head;
            }
        }

        nodes.put(node.key,node);
    }

    /**
     * 获取元素
     * @param t
     * @return
     */
    public V getCache(K t){

        Node<K,V> node = nodes.get(t);

        if(node != null){
            V v =  node.value;
            //将当前节点放到双向链表头部
            this.afterNodeAccess(node);
            return v;
        }
        return null;
    }

    /**
     * 将node写入双向链表头
     * @param node
     */
    private void afterNodeAccess(Node<K,V> node) {

        Node p = node,a = p.after, b=p.before;

        p.before = null;
        //进行替换

        //说明当前节点是head
        if(b == null){
            return;
        }else {
            b.after = a;
        }
        //说明当前节点为tail
        if(a == null ){
           this.tail = b;
        }else{
            a.before = b;
        }
        head.before = p;
        p.after = head;
        head = p;
    }

    /**
     * 循环迭代
     */
    public void forEach(BiConsumer<? super K, ? super V> action) {

        if (action == null) {
            throw new NullPointerException();
        }
        for (Node<K,V> e = head; e != null; e = e.after) {
            action.accept(e.key, e.value);
        }

    }

}

测试代码:

public static void main(String[] args) {

        int maxSize = 6 ;

        MyLRUCache myLRUCache = new MyLRUCache(maxSize);

        //构建测试数据
        for (int i=0;i<6;i++){
            myLRUCache.putCaceh("test_key_"+i,i);
        }

        myLRUCache.getCache("test_key_1");
        myLRUCache.getCache("test_key_5");

        myLRUCache.putCaceh("test_key_7",7);
        myLRUCache.putCaceh("test_key_8",8);
        myLRUCache.getCache("test_key_1");
        myLRUCache.getCache("test_key_5");
        myLRUCache.putCaceh("test_key_9",9);
        myLRUCache.putCaceh("test_key_10",10);
        myLRUCache.getCache("test_key_1");
        myLRUCache.getCache("test_key_5");
        myLRUCache.getCache("test_key_8");
        myLRUCache.putCaceh("test_key_5",55);


        //按照LRU算法 最终的结果为 55(最新数据),8,1,10,9,7(最old数据)
        myLRUCache.forEach((k,v)->{
            System.out.print(v+",");
        });

    }

最终运行的结果如下图所示:

 

最终结果与期盼的结果值保持一致 

2.2:基于Java中LinkedHashMap实现

从Java中LinkedHashMap底层实现可以知道LinkedHashMap的排序特性和LRU算法不谋而合。

/**
 *使用LinkedHashMap实现LRU算法
 *
 * @author fangyuan
 *
 */
public class LRUCache  extends LinkedHashMap {

    /**
     * 使用LRU算法构建的缓存中保存的最大数据
     */
    private Integer maxSize;

    public LRUCache( Integer maxSize){
        super(16,0.75F,true);
        this.maxSize = maxSize;
    }

    /**
     * 重写removeEldestEntry,按照LRU算法,当达到内存最大深度时,移除最年长的数据(不经常被访问的数据)
     * @param eldest
     * @return
     */
    @Override
    protected boolean removeEldestEntry(Map.Entry eldest) {
        return this.maxSize<this.size();
    }

}

测试代码: 

/**
 * LRUCache测试
 * @author fangyuan
 */
public class LRUCacheTest {

    public static void main(String[] args) {

        int maxSize = 6 ;

        LRUCache lruCache = new LRUCache(maxSize);

        //构建测试数据
        for (int i=0;i<6;i++){
            lruCache.put("test_key_"+i,i);
        }

        lruCache.get("test_key_1");
        lruCache.get("test_key_5");

        lruCache.put("test_key_7",7);
        lruCache.put("test_key_8",8);
        lruCache.get("test_key_1");
        lruCache.get("test_key_5");
        lruCache.put("test_key_9",9);
        lruCache.put("test_key_10",10);
        lruCache.get("test_key_1");
        lruCache.get("test_key_5");
        lruCache.get("test_key_8");

        //按照LRU算法 最终的结果为 7(最old数据),9,10,1,5,8(最新数据)
        lruCache.forEach((k,v)->{
            System.out.print(v+",");
        });

    }

}

最终运行的结果如下图所示: 

最终结果与期盼的结果值保持一致 

Java实现LRU(最近最少使用)算法 通过实现LRU算法,我们可以在有限的缓存容量下,有效地提高数据的命中率,减少不必要的数据访问开销。在Java中,我们可以选择使用双向链表和哈希表的组合,或者直接利用来实现LRU缓存。前者提供了更多的灵活性和控制能力,而后者则更加简洁和高效。根据具体的应用场景和需求,我们可以选择合适的实现方式。版权声明:本博客内容为原创,转载请保留原文链接及作者信息。 阅读详情

相关推荐

Java实现一个LRU算法

LRU缓存淘汰策略 LRU(最近最少使用)是一种高效的缓存淘汰算法,其核心思想是优先淘汰最久未被访问的数据。该策略通过哈希表和双向链表实现:哈希表提供O(1)时间复杂度的数据查找,双向链表维护数据访问顺序(头部存最新访问数据,尾部存最久未访问数据)。当缓存满时,直接删除链表尾部节点即可。这种设计既保证了快速访问,又能高效维护数据的时效性,广泛应用于数据库缓存、页面置换等场景。

lagrahhn的博客 1032

LRU(JAVA简洁版)

一、算法介绍 最近最久未使用(Least Recently Used LRU)算法是⼀种缓存淘汰策略,它是大部分操作系统为最大化页面命中率而广泛采用的一种页面置换算法。该算法的思路是,发生缺页中断时,将最近一段时间内最久未使用的页面置换出去。 从程序运行的原理来看,最近最久未使用算法是比较接近理想的一种页面置换算法,这种算法既充分利用了内存中页面调用的历史信息,又正确反映了程序的局部问题。 虚拟页式存储管理,则是将进程所需空间划分为多个页面,内存中只存放当前所需页面,其余页面放入外存的管理方式。 ..

上山的人 1万+

Java实现代码LRU算法

LRU算法 + Java实现代码 LRU原理 LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。 最常见的实现是使用一个链表保存缓存数据,详细算法实现如下 新数据插入到链表头部; 每当缓存命中(即缓存数据被访问),则将数据移到链表头部; 当链表满的时候,将链表尾部的数据丢弃。 【命中率】 当存在热点数据时,LRU的效率很好,但偶发性的、周期性的批量操作会导致LRU命中率急剧下降,缓存污染

xingdianp的博客 441

java中LRU算法

当我们处理大量数据时,经常需要使用缓存来提高性能。LRU(最近最少使用)算法是一种常用的缓存淘汰策略,用于在缓存空间不足时选择要删除的数据。首先,我们需要了解LRU算法的工作原理。LRU算法的核心思想是基于数据的访问模式:最近被访问的数据很可能在不久的将来再次被访问,而最久未被访问的数据可能很快就会被废弃。LRU算法基于这个思想,将最近访问的数据保留在缓存中,而淘汰最久未被访问的数据。除了使用来实现LRU算法外,我们还可以通过自定义数据结构来实现。

m0_68642284的博客 1488

LRU算法 + Java实现代码

LRU原理 LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。 最常见的实现是使用一个链表保存缓存数据,详细算法实现如下 新数据插入到链表头部; 每当缓存命中(即缓存数据被访问),则将数据移到链表头部; 当链表满的时候,将链表尾部的数据丢弃。 【命中率】 当存在热...

Mr_HHH的博客 885

基于Java实现LRU算法

目录 一、什么是LRU 二、 选用LinkedHashMap实现 一、什么是LRU LRU是指最近最少使用,是一种缓存淘汰算法。根据数据的历史访问记录来进行淘汰数据,把最近一次使用时间离现在时间最远的数据删除掉,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。 以下摘自百度百科: LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问...

Harrison 1776

Java 实现 LRU 算法

1 什么是LRU LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。 2 实现思路 开始时,内存中没有页面。 每次访问页面时,先检测内存中是否存在该页面,若不存在则将该页面加载到内存“末尾”,若存在则直接访问该页面,并将该页面移到内存“末尾”。 如果访问某个内存中不存在的页面时,内存已满,则将内存“开头”的页面移出,并将新的页面加载到内存“末尾”。 这样就可以始终保持着最近访问的页面在不经常访问的页面的后面了。 3数据结构的选择

冰茶不冰的博客 4471

告别蓝牙音质妥协:用ESP32和PCM5102搭建WiFi无损音频播放器(附完整代码)

本文详细介绍了如何利用ESP32微控制器和PCM5102 DAC芯片构建一套完整的WiFi无损音频流媒体系统,彻底摆脱蓝牙协议的音质束缚。从硬件原理到软件实现,包括核心器件选型、电路设计、I2S音频驱动实现以及系统优化方案,帮助音频发烧友实现高保真无线音频传输。

weixin_30733003的博客 542

LRU算法(java实现)

Java实现LRU算法算法导入一、虚拟存储器的基本工作情况二、页面置换算法算法分析算法设计一、实现栈:二、实现主类:三、盲目分析四、敲代码算法源码及运行结果算法总结 算法导入        哈喽小伙伴们,英俊的我又回来了哈哈哈。今天给大家带来的是操作系统中的页面置换算法LRU算法实现。    &nb...

我家有只小金毛的博客 5882

数据包络分析(超效率-SBM模型)附python代码

超效率-SBM模型超效率SBMpython代码(部分) 这段时间差不多忙完了,终于有时间可以来经营我的博客了。 上阵子挺多人私信我,原谅我记性不好,可能没有回复全。 这篇文章是超效率的扩展。 超效率SBM SBM本身就是非径向模型(non-radial model),想要了解径向超效率的请自行去前面翻阅。 上篇文章说到super-SBM的一个模型,公式为: 这个模型是分式模型,我们可以通过charnes cooper变换,将其转变成为: python代码(部分) 在编程过程中,本来我以为第一个模型是无

weixin_43217288的博客 3万+

关于token无痛刷新的两个方案

目录方案一方案二 方案一 思路: 后端需要返回一个token过期的时间,在请求发起前拦截每个请求,判断token的有效时间是否已经过期,如果已过期,则暂时将请求挂起,先刷新token后再继续请求。 前期思考: 返回过期时间是为了判断是否过期的,但是如果服务器时间和系统时间不一致呢? 如果同时发起多个请求时怎么办? 实现: 因为是在请求前进行拦截,所以这里用axios的axios.interceptors.request.use()方法 首先,关于服务器时间和系统时间不一致的问题,我的解决方法是:

Yugoup的博客 2716

LRU算法 java实现

定义:LRU全称Least Recently Used,也就是最近最少使用的意思,是一种内存管理算法,最早应用于Linux系统。 LRU算法基于一种假设:长期不使用的数据,在未来被用到的几率也不大。因此当数据所占内存达到一个阈值是,可以选择移除掉最近最少被使用的数据来保持内存的高效使用,这是基于时间局部性原理的一个假设。LRU算法主要用于缓存算法,在节省资源的情况下提高数据访问效率。 LRU使...

leo_weile的博客 7969

告别连接难题:Windows 11下Multisim主数据库稳定运行终极配置指南

本文详细解析了Windows 11下Multisim 14.0主数据库连接失败的三大根源,并提供了四步终极解决方案,包括系统环境优化、软件权限配置、注册表修复和网络验证绕过技巧。通过实测数据对比,本方案显著提升了启动速度和稳定性,解决了电子仿真中的常见连接问题。

weixin_33738555的博客 432

LRU算法及Java实现

LRU算法介绍 LRU是Least Recently Used的缩写,即最近最少使用,常用于页面置换算法,为虚拟页式存储管理服务。LRU算法的提出,是基于这样一个事实:在前面几条指令中使用频繁的页面很可能在后面的几条指令中频繁使用。反过来说,已经很久没有使用的页面很可能在未来较长的一段时间内不会被用到。这个,就是著名的局部性原理。此外,LRU算法也经常被用作缓存淘汰策略。本文将基于LRU算法的思想...

To be a great coder 1万+

DeerFlow 系列教程 第三篇 | 核心技术深度剖析:Skills、Memory 与 Context Engineering

摘要化是 Context Engineering 中最关键的组件——它直接决定了长对话的可用性。Skills 技能系统通过渐进式加载的三层模型,在保持系统提示词轻量的同时,支持无限数量的技能扩展。从发现到执行的 10 个生命周期阶段,配合 AI 驱动的安全扫描和多层缓存,构成了一个生产级的技能管理框架。Memory 长期记忆系统通过文件系统持久化、LLM 驱动的信息提取和防抖动异步更新,实现了跨会话的认知持久化。六类事实分类体系和修正信号检测机制,让 Agent 能够从交互中持续学习和改进。

weixin_43674738的博客 280

Challenge 4 - OSCP A

在c盘下发现一个windows.old,在里面可以找到SYSTEM和SAM文件,下载到本地,利用samdump2解密发现没解出来,再来试试pwdump.py(https://github.com/CiscoCXSecurity/creddump7)得到压缩包密码bludecode,解压之后发现一个比较特殊的文件configuration.php,里面有两个类似密码的字符串。登录之后在/opt/backups/下发现几个特殊文件,其中sitebackup3.zip是个正常的压缩包。但是这个压缩包是有密码的。

羽的博客 5786

LRU算法Java实现

LRU(The Least Recently Used)即最近最少使用算法。其原理是如果一个数据最近没有被使用,那么将来它被使用的可能也更低,因此在内存达到一定阈值时,将最近最少使用的数据淘汰的一种策略算法。

MagicianTech的博客 2094

一键开关机电路

一键开关机电路

让你爱上电路设计 4180

LRU算法的Java实现

LRU原理 LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。 实现方式 要实现LRU算法,有 2 种实现方式。 第一种,是使用Java中现成的API —— LinkedHashMap。它在HashMap的基础增加了按照访问顺序排序的功能,非常适合LRU的实现。 代码如下: /...

makersy的博客 536

3、流程引擎下载安装与部署

camunda有多种使用方式,此处先使用独立平台的方式部署引擎,这种用法适合分布式,微服务化,多语言异构系统的使用方式。

leyoliu的博客 5520

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

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

java 实现lru算法_LRU算法,LRU算法怎么实现?

下面要给大家介绍的就是和LRU算法有关的内容,你知道LRU算法应该怎样实现吗?实现的方式有哪些呢?一起来了解一下吧。LRU算法实现哈希链表结构:packageblogSrc;importjava.util.HashMap;publicclassLRUCache{privateNodehead;privateNodeend;privateHashMaphashMap;priva...

weixin_35828992的博客 137

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

java lru算法栈_LRU算法的Java实现

一、LRU算法介绍LRU算法全称Least Recently Used,也就是检查最近最少使用的数据的算法。这个算法通常使用在内存淘汰策略中,用于将不常用的数据转移出内存,将空间腾给最近更常用的“热点数据”。算法很简单,只需要将所有数据按使用时间排序,在需要筛选出LRU数据时,取排名靠后的即可。二、Java中的LRU实现思路根据LRU算法,在Java中实现需要这些条件:底层数据使用双向链表,方便在...

weixin_39999781的博客 319

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Java 实现 LRU 算法详解

LRU 算法的核心思想是,如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。当缓存空间已满时,最久没有被访问的数据将被淘汰,为新的数据腾出空间。通过使用 Java 实现 LRU 算法,我们可以有效地管理缓存,提高程序的性能。在实际应用中,LRU 算法可以用于数据库缓存、Web 服务器缓存等场景。希望本文对你理解和实现 LRU 算法有所帮助。

dawn191228的博客 1265
上一篇: Java中LinkedHashMap底层实现
下一篇: 算法数据结构-Trie树
F_Hello_World
博客等级 码龄11年 38粉丝 58原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值