zoukankan      html  css  js  c++  java
  • LRU算法简单实现

     什么是LRU

    LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”

    距离现在最早使用的会被我们替换掉。不够形象的话我们看下面的例子。

    size=3的缓存淘汰实现:

    在插入元素1的时候,位置1、2、3依次为1、null、null

    在插入元素2的时候,位置1、2、3依次为1、2、null

    ....

    在插入元素4的时候,位置1、2、3依次为2、3、4,本来位置1的元素1被淘汰

    利用LinkedHashMap实现的简单LRU

    import java.util.LinkedHashMap;
    import java.util.Map;
    
    public class UseLinkedHashMapCache<K,V> extends LinkedHashMap<K,V> {
    
        private final int cacheSize;
        /**
         * 传递进来最多能缓存多少数据
         *
         * @param cacheSize 缓存大小
         */
        public UseLinkedHashMapCache(int cacheSize) {
            // true 表示让 linkedHashMap 按照访问顺序来进行排序,最近访问的放在头部,最老访问的放在尾部。
            super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);
            this.cacheSize = cacheSize;
        }
    
        @Override
        protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
            // 当 map中的数据量大于指定的缓存个数的时候,就自动删除最老的数据。
            return size() > cacheSize;  
        }
    }

    这里需要注意初始容量大小:

     //缓存最大容量 => initialCapacity * DEFAULT_LOAD_FACTOR,避免扩容操作
     int initialCapacity = (int) Math.ceil(maxCacheSie / DEFAULT_LOAD_FACTOR) + 1;

    看一下LinkedHashMap的构造方法:

        /**
         * Constructs an empty <tt>LinkedHashMap</tt> instance with the
         * specified initial capacity, load factor and ordering mode.
         *
         * @param  initialCapacity the initial capacity
         * @param  loadFactor      the load factor
         * @param  accessOrder     the ordering mode - <tt>true</tt> for
         *         access-order, <tt>false</tt> for insertion-order
         * @throws IllegalArgumentException if the initial capacity is negative
         *         or the load factor is nonpositive
         */
        public LinkedHashMap(int initialCapacity,
                             float loadFactor,
                             boolean accessOrder) {
            super(initialCapacity, loadFactor);
            this.accessOrder = accessOrder;
        }

    accessOrder有两种模式,如果设置为true的话是按照访问排序,设置是false的话是按照插入顺序排序

    然后在看一下我们重写的removeEldestEntry方法:

        /**
         * Returns <tt>true</tt> if this map should remove its eldest entry.
         * This method is invoked by <tt>put</tt> and <tt>putAll</tt> after
         * inserting a new entry into the map.  It provides the implementor
         * with the opportunity to remove the eldest entry each time a new one
         * is added.  This is useful if the map represents a cache: it allows
         * the map to reduce memory consumption by deleting stale entries.
         *
         * <p>Sample use: this override will allow the map to grow up to 100
         * entries and then delete the eldest entry each time a new entry is
         * added, maintaining a steady state of 100 entries.
         * <pre>
         *     private static final int MAX_ENTRIES = 100;
         *
         *     protected boolean removeEldestEntry(Map.Entry eldest) {
         *        return size() &gt; MAX_ENTRIES;
         *     }
         * </pre>
         *
         * <p>This method typically does not modify the map in any way,
         * instead allowing the map to modify itself as directed by its
         * return value.  It <i>is</i> permitted for this method to modify
         * the map directly, but if it does so, it <i>must</i> return
         * <tt>false</tt> (indicating that the map should not attempt any
         * further modification).  The effects of returning <tt>true</tt>
         * after modifying the map from within this method are unspecified.
         *
         * <p>This implementation merely returns <tt>false</tt> (so that this
         * map acts like a normal map - the eldest element is never removed).
         *
         * @param    eldest The least recently inserted entry in the map, or if
         *           this is an access-ordered map, the least recently accessed
         *           entry.  This is the entry that will be removed it this
         *           method returns <tt>true</tt>.  If the map was empty prior
         *           to the <tt>put</tt> or <tt>putAll</tt> invocation resulting
         *           in this invocation, this will be the entry that was just
         *           inserted; in other words, if the map contains a single
         *           entry, the eldest entry is also the newest.
         * @return   <tt>true</tt> if the eldest entry should be removed
         *           from the map; <tt>false</tt> if it should be retained.
         */
        protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
            return false;
        }

    在每次插入元素(put或者putAll)会调用该方法,如果返回true的话,则会删除该map的最早插入的那个元素。所以当这个map要作为缓存的时候,在map存储不下更多的元素时候,把最老的那个元素删除来减少内存消耗

    测试

    public class TestLRU {
    
            public static void main(String[] args) {
                UseLinkedHashMapCache<Integer,String> cache = new UseLinkedHashMapCache<>(4);
                cache.put(1, "one");
                cache.put(2, "two");
                cache.put(3, "three");
                cache.put(4, "four");
                cache.put(2, "two");for (Integer key : cache.keySet()) {
                    System.out.println("Key:	"+key);
                }
            }
    }

    输出结果(按照访问顺序来淘汰):

    Key:    1
    Key:    3
    Key:    4
    Key:    2

    然后把之前构造方法中的accessOrder模式改为false(也就是按插入顺序来淘汰)

    输出结果:

    Key:    1
    Key:    2
    Key:    3
    Key:    4

    整理自:

    https://blog.csdn.net/nakiri_arisu/article/details/79205660

    https://blog.csdn.net/u012485480/article/details/82427037

  • 相关阅读:
    eclipse/intellij idea 查看java源码和注释
    理解线程池,看这篇足够了-转
    乐观锁的幂等性方案
    springboot2.0以后的junit
    详解 Java 中的三种代理模式
    MYSQL慢查询配置
    MySQL 数据库性能优化之SQL优化【转】
    SQL中EXPLAIN命令详解---(转)
    spring的面试
    sql joins 7
  • 原文地址:https://www.cnblogs.com/zz-ksw/p/12425565.html
Copyright © 2011-2022 走看看