轻松扩展LinkedHashMap类实现LRU算法

来源:互联网 发布:手机淘宝卖家开店 编辑:程序博客网 时间:2024/05/17 05:03
      今天偶然看到某框架源码自带的简单缓存策略算法LRU的实现,不想就几行代码即实现,原来只是简单的扩展了 jdk自带的
LinkedHashMap类,如此简单,故分享之。
  
     具体关于 
LinkedHashMap 的描述 不懂的自己去看 jdk api 文档,这里只说说怎么实现,翻开 LinkedHashMap 源码 我们可以看到一段描述:
         
     /**
     * 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() > MAX_ENTRIES;
     *     } 
  **/

     
 protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return false;
    } 

   意思就是说 在 put() 或者 putAll()  操作后会调用此方法判断 是否需要 清除最旧的那个元素,默认是返回 false,即不做操作。注意此 方法 是 protected ,即用于子类覆盖的,可以说这是 jdk的开发者特意留下来为我们实现LRU提供的,注释也说了,我们可以简单的覆盖此方法实现 LRU ,如:

  
public class LruCache implements Cache {
    
    private final Map<Object, Object> store;
    private int initialCapacity = 16;
    private float loadFactor = 0.75f;
    private boolean accessOrder = true;

    public LruCache(URL url) {
        final int max = 1000;  // 缓存中最多1000个元素
        this.store = new LinkedHashMap<Object, Object>(initialCapacity,loadFactor,accessOrder){
            private static final long serialVersionUID = -3834209229668463829L;
            @Override
            protected boolean removeEldestEntry(Entry<Object, Object> eldest) {
                return size() > max;
            }
        };
    } 
}

 这样当 stroe 中的元素超过 max=1000个时,将从 map 中删除 最旧的那个元素,即实现了  LRU。
 需要注意的是, 
LinkedHashMap 并未覆盖 父类 HashMap中的 put() 和 putAll() ,而是覆盖了 会被 put() 调用的 addEntry() 方法,我们来看下 LinkedHashMap 中的 addEntry() :

     
void addEntry(int hash, K key, V value, int bucketIndex) {
        createEntry(hash, key, value, bucketIndex);

        // Remove eldest entry if instructed, else grow capacity if appropriate
        Entry<K,V> eldest = header.after;
        if (removeEldestEntry(eldest)) {
            removeEntryForKey(eldest.key);
        } else {
            if (size >= threshold)
                resize(2 * table.length);
        }
    } 

  看到了吧 ,如果返回为 true,则会删除最旧的那个元素,so simple

  ps: 如果在多线程环境下使用,由于其父类 HashMap不支持同步,所以需要重写 get put 方法,无非就是加个同步:

   public void put(Object key, Object value) {
        synchronized (store) {
            store.put(key, value);
        }
    }


    public Object get(Object key) {
        synchronized (store) {
            return store.get(key);
        }
    }
原创粉丝点击