LruCache源码解析

作者: zhangxuanchen | 来源:发表于2017-02-11 08:14 被阅读4次

    LruCache 内部相当于维护了一个LinkedHashMap

    /**
    * @param maxSize for caches that do not override {@link #sizeOf}, this is
    *     the maximum number of entries in the cache. For all other caches,
    *     this is the maximum sum of the sizes of the entries in this cache.
    */
    public LruCache(int maxSize) {
            if (maxSize <= 0) {
                throw new IllegalArgumentException("maxSize <= 0");
            }
            this.maxSize = maxSize;
            this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
    }
    

    LinkedHashMap 结构为一个双向链表,对照看一下他的构造函数

    //双向链表中元素排序规则的标志位。  
    //accessOrder为false,表示按插入顺序排序  
    //accessOrder为true,表示按访问顺序排序  
    private final boolean accessOrder;  
    
    //调用HashMap的构造方法来构造底层的数组  
    public LinkedHashMap(int initialCapacity, float loadFactor) {  
       super(initialCapacity, loadFactor);  
       accessOrder = false;    //链表中的元素默认按照插入顺序排序  
     }  
    
    //覆写HashMap中的get方法,通过getEntry方法获取Entry对象。  
    //注意这里的recordAccess方法,  
    //如果链表中元素的排序规则是按照插入的先后顺序排序的话,该方法什么也不做,  
    //如果链表中元素的排序规则是按照访问的先后顺序排序的话,则将e移到链表的末尾处。  
    public V get(Object key) {  
         Entry<K,V> e = (Entry<K,V>)getEntry(key);  
         if (e == null)  
              return null;  
         e.recordAccess(this);  
         return e.value;  
    }  
      
    //覆写HashMap中的recordAccess方法(HashMap中该方法为空),  
    //当调用父类的put方法,在发现插入的key已经存在时,会调用该方法,  
    //调用LinkedHashmap覆写的get方法时,也会调用到该方法,  
    //该方法提供了LRU算法的实现,它将最近使用的Entry放到双向循环链表的尾部,  
    //accessOrder为true时,get方法会调用recordAccess方法  
    //put方法在覆盖key-value对时也会调用recordAccess方法  
    //它们导致Entry最近使用,因此将其移到双向链表的末尾  
    void recordAccess(HashMap<K,V> m) {  
        LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;  
    //如果链表中元素按照访问顺序排序,则将当前访问的Entry移到双向循环链表的尾部,  
    //如果是按照插入的先后顺序排序,则不做任何事情。  
        if (lm.accessOrder) {  
            lm.modCount++;  
            //移除当前访问的Entry  
            remove();  
            //将当前访问的Entry插入到链表的尾部  
            addBefore(lm.header);  
           }  
    }  
    
    //双向循环立链表中,将当前的Entry插入到existingEntry的前面  
    private void addBefore(Entry<K,V> existingEntry) {  
                after  = existingEntry;  
                before = existingEntry.before;  
                before.after = this;  
                after.before = this;  
            }  
      
    

    可以看到accessOrder参数决定LinkedHashMap以什么方式排序,当里面的节点被访问后,如果accessOrder为true他就会被移到头节点上面。来保持以访问顺序排序

    相关文章

      网友评论

        本文标题:LruCache源码解析

        本文链接:https://www.haomeiwen.com/subject/myrnittx.html