zoukankan      html  css  js  c++  java
  • 如何使用LinkedHashMap来实现一个LruCache

    最近在看mybatis的源代码,发现了mybatis中实现的LruCache使用到了LinkedHashMap,所以就探究了一下LinkedHashMap是如何支持Lru缓存的

    LinkedHashMap内部维护了一个所有的Entity的双向链表

    同时构造方法可以设置Iterator的时候,是按照插入的顺序排序还是按照访问的顺序排序

    默认是按照插入的顺序来排序的,在构造方法里边可以设置按照访问的顺序来排序

    那究竟按照访问的顺序来排序是什么意思呢?

    LinkedHashMap的get(key)方法是自己实现的,并没有从HashMap里边继承,我们看看get(Key)方法的实现是什么样子的

    我们看afterNodeAccess()方法是如何实现的

    这个方法主要就是移动双向链表的指针,将传入的结点移动到LinkedHashMap维护的双向链表的末尾,这样每次通过get(key)方法访问一个元素,这个元素就会被移动到双向链表的末尾,按照访问的顺序来排序,就是每次通过Iterator来遍历keySet或者是EntrySet的时候,访问过的元素会出现在最后边(因为LinedHashMap的Iterator遍历的时候,遍历的是内部的双向链表,从头结点,遍历到尾结点)

    顺着这样的思路,如果在满足一定条件的情况下,移除掉双向链表的头结点,这样就实现了一个LruCahe

    其实LinkedHashMap已经为我们提供了这样的方法,LinkedHashMap中有一个方法removeEldestEntry(entry) 我们只需要覆盖这个方法,根据我们自己的需求在一定条件下返回true,这样就实现了LruCache
    改方法的默认实现是返回false
    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
    return false;
    }

    LinkedHashMap的afterNodeInsertion()方法会根据其他条件以及removeEldestEntry的返回值来决定是否删除到双向链表的表头元素

    依据此,我们使用LinkedHashMap来实现一个最简单的Lru缓存如下:
    import org.junit.Test;

    import java.util.LinkedHashMap;
    import java.util.Map;
    public class TestCache {
        @Test
        public void testLinkedHashMap() {
            LinkedHashMap<String, String> map = new LinkedHashMap<String, String>(5, 0.75F, true) {
                @Override
                protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
                    //当LinkHashMap的容量大于等于5的时候,再插入就移除旧的元素
                    return this.size() >= 5;
                }
            };
            map.put("aa", "bb");
            map.put("cc", "dd");
            map.put("ee", "ff");
            map.put("gg", "hh");
            print(map);
            map.get("cc");
            System.out.println("===================================");
            print(map);
    
            map.get("ee");
            map.get("aa");
            System.out.println("====================================");
            map.put("ss","oo");
            print(map);
        }
    
        void print(LinkedHashMap<String, String> source) {
            source.keySet().iterator().forEachRemaining(System.out::println);
        }
    }   
    

    Mybatis中的Lrucache实现也是类似的思路,比较简单,下边是关键的代码:

    构造方法中调用了setSize()方法,默认缓存1024个元素

    public LruCache(Cache delegate) {
        this.delegate = delegate;
        setSize(1024);
      }
    

    setSize()方法中初始化了HashMap,并实现了removeEldestEntry()方法

    public void setSize(final int size) {
        keyMap = new LinkedHashMap<Object, Object>(size, .75F, true) {
          private static final long serialVersionUID = 4267176411845948333L;
    
          @Override
          protected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {
            boolean tooBig = size() > size;
            if (tooBig) {
              eldestKey = eldest.getKey();
            }
            return tooBig;
          }
        };
      }
  • 相关阅读:
    learnyou 相关网站
    hdu 3038 How Many Answers Are Wrong
    hdu 3047 Zjnu Stadium 并查集高级应用
    poj 1703 Find them, Catch them
    poj 1182 食物链 (带关系的并查集)
    hdu 1233 还是畅通工程
    hdu 1325 Is It A Tree?
    hdu 1856 More is better
    hdu 1272 小希的迷宫
    POJ – 2524 Ubiquitous Religions
  • 原文地址:https://www.cnblogs.com/jiaoyiping/p/10604463.html
Copyright © 2011-2022 走看看