Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 320|回复: 0

[servlet学习]基于双链表实现缓存策略之LRU实现

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-10-10 04:00:14 | 显示全部楼层 |阅读模式
    缓存在应用中的作用,相信不用多说,对性能是具有质的提升的,而目前的缓存策略常用的FIFO,LRU等等。    今天来探讨一下 LRU这种缓存策略的底层原理与实现。   首先,来看看LRU的定义: Least recently used. 可以理解为, 最少使用的被淘汰。     今天主要来讨论基于双链表的LRU算法的实现, 在讨论之前,我们需要了解一下,传统LRU算法的实现,与其的弊端。    传统意义的LRU算法是为每一个Cache对象设置一个计数器,每次Cache命中则给计数器+1,而Cache用完,需要淘汰旧内容,放置新内容时,就查看所有的计数器,并将最少使用的内容替换掉。

        它的弊端很明显,如果Cache的数量少,问题不会很大, 但是如果Cache的空间过大,达到10W或者100W以上,一旦需要淘汰,则需要遍历所有计算器,其性能与资源消耗是巨大的。效率也就非常的慢了。  
      
       
       
         
       

         
       
      
         基于这样的情况,所有就有新的LRU算法的实现----基于双链表 的LRU实现。     它的原理: 将Cache的所有位置都用双连表连接起来,当一个位置被命中之后,就将通过调整链表的指向,将该位置调整到链表头的位置,新加入的Cache直接加到链表头中。      这样,在多次进行Cache操作后,最近被命中的,就会被向链表头方向移动,而没有命中的,而想链表后面移动,链表尾则表示最近最少使用的Cache。      当需要替换内容时候,链表的最后位置就是最少被命中的位置,我们只需要淘汰链表最后的部分即可。   上面说了这么多的理论, 下面用代码来实现一个LRU策略的缓存。      我们用一个对象来表示Cache,并实现双链表, public class LRUCache {
            /**
             * 链表节点
             * @author Administrator
             *
             */
            class CacheNode {
                    ……
            }
            private int cacheSize;//缓存大小
            private Hashtable nodes;//缓存容器
            private int currentSize;//当前缓存对象数量
            private CacheNode first;//(实现双链表)链表头
            private CacheNode last;//(实现双链表)链表尾
    }
                      [/code]  下面给出完整的实现,这个类也被Tomcat所使用( org.apache.tomcat.util.collections.LRUCache),但是在tomcat6.x版本中,已经被弃用,使用另外其他的缓存类来替代它。 public class LRUCache {
            /**
             * 链表节点
             * @author Administrator
             *
             */
            class CacheNode {
                    CacheNode prev;//前一节点
                    CacheNode next;//后一节点
                    Object value;//值
                    Object key;//键
                    CacheNode() {
                    }
            }
            public LRUCache(int i) {
                    currentSize = 0;
                    cacheSize = i;
                    nodes = new Hashtable(i);//缓存容器
            }
           
            /**
             * 获取缓存中对象
             * @param key
             * @return
             */
            public Object get(Object key) {
                    CacheNode node = (CacheNode) nodes.get(key);
                    if (node != null) {
                            moveToHead(node);
                            return node.value;
                    } else {
                            return null;
                    }
            }
           
            /**
             * 添加缓存
             * @param key
             * @param value
             */
            public void put(Object key, Object value) {
                    CacheNode node = (CacheNode) nodes.get(key);
                   
                    if (node == null) {
                            //缓存容器是否已经超过大小.
                            if (currentSize >= cacheSize) {
                                    if (last != null)//将最少使用的删除
                                            nodes.remove(last.key);
                                    removeLast();
                            } else {
                                    currentSize++;
                            }
                           
                            node = new CacheNode();
                    }
                    node.value = value;
                    node.key = key;
                    //将最新使用的节点放到链表头,表示最新使用的.
                    moveToHead(node);
                    nodes.put(key, node);
            }
            /**
             * 将缓存删除
             * @param key
             * @return
             */
            public Object remove(Object key) {
                    CacheNode node = (CacheNode) nodes.get(key);
                    if (node != null) {
                            if (node.prev != null) {
                                    node.prev.next = node.next;
                            }
                            if (node.next != null) {
                                    node.next.prev = node.prev;
                            }
                            if (last == node)
                                    last = node.prev;
                            if (first == node)
                                    first = node.next;
                    }
                    return node;
            }
            public void clear() {
                    first = null;
                    last = null;
            }
            /**
             * 删除链表尾部节点
             *  表示 删除最少使用的缓存对象
             */
            private void removeLast() {
                    //链表尾不为空,则将链表尾指向null. 删除连表尾(删除最少使用的缓存对象)
                    if (last != null) {
                            if (last.prev != null)
                                    last.prev.next = null;
                            else
                                    first = null;
                            last = last.prev;
                    }
            }
           
            /**
             * 移动到链表头,表示这个节点是最新使用过的
             * @param node
             */
            private void moveToHead(CacheNode node) {
                    if (node == first)
                            return;
                    if (node.prev != null)
                            node.prev.next = node.next;
                    if (node.next != null)
                            node.next.prev = node.prev;
                    if (last == node)
                            last = node.prev;
                    if (first != null) {
                            node.next = first;
                            first.prev = node;
                    }
                    first = node;
                    node.prev = null;
                    if (last == null)
                            last = first;
            }
            private int cacheSize;
            private Hashtable nodes;//缓存容器
            private int currentSize;
            private CacheNode first;//链表头
            private CacheNode last;//链表尾
    }[/code]

      
      
       
       

         
       

         
       
      
    复制代码

    源码下载:http://file.javaxxz.com/2014/10/10/040014312.zip
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-5-8 05:27 , Processed in 0.319643 second(s), 38 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表