LinkedHashMap 是如何实现的

LinkedHash 底层基于 HashMap 实现并扩展了 HashMap.Node 使其支持双向链表

LinkedHashMap 两种有序

1. 插入有序

示例代码:

        HashMap<String, Integer> hashMap = new HashMap<>();
        LinkedHashMap<String, Integer> linkedHashMap = new LinkedHashMap<>();
        for (int i = 0; i < 10; i++) {
            hashMap.put("index-" + i, i);
            linkedHashMap.put("index-" + i, i);
        }

        System.out.println(hashMap);
        System.out.println(linkedHashMap);

输出:

{index-0=0, index-1=1, index-2=2, index-7=7, index-8=8, index-9=9, index-3=3, index-4=4, index-5=5, index-6=6}
{index-0=0, index-1=1, index-2=2, index-3=3, index-4=4, index-5=5, index-6=6, index-7=7, index-8=8, index-9=9}

可以注意到 HashMap 由于 Hash 算法的特性,遍历输出并不是顺序。 LinkedHashMap虽然实现基于 hashMap 由于内部维护了双向链表所以支持按照插入顺序进行输出。

2.访问有序 (当 accessOrder = true)

示例代码:

    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 4, 8, 2, 55, 3, 4, 8, 6, 4, 0, 11, 34, 90, 23, 54, 77, 9, 2, 9, 4, 10);
        System.out.println(slow(numbers));
        HashMap<String, Integer> hashMap = new HashMap<>();
        LinkedHashMap<String, Integer> linkedHashMap = new LinkedHashMap<>(10, 1, true);
        for (int i = 0; i < 10; i++) {
            hashMap.put("index-" + i, i);
            linkedHashMap.put("index-" + i, i);
        }

        for (int i = 5; i >= 0; i--) {
            linkedHashMap.get("index-" + i);
        }

        System.out.println(hashMap);
        System.out.println(linkedHashMap);
    }

输出:

{index-0=0, index-1=1, index-2=2, index-7=7, index-8=8, index-9=9, index-3=3, index-4=4, index-5=5, index-6=6}
{index-6=6, index-7=7, index-8=8, index-9=9, index-5=5, index-4=4, index-3=3, index-2=2, index-1=1, index-0=0}

当某个元素被访问后将此元素移动在链表尾部,基于此特性我们可以实现 LRU (Least Recently Used) 即在内存缓存或分布式缓存中常见的清理策略。

基于 LinkedHashMap 实现 LRU

基于 LinkedHashMap 实现 LRU 共有如下几步

  1. 继承 LinkedHashMap 或包装LinedHashMap
  2. 设定 LinkedHashMap 按照访问排序
  3. 确定 LRU 容器最大容量
  4. 重写 removeEldestEntry 方法保证容器长度固定

示例代码:

public class LRU<K,V> extends LinkedHashMap<K, V> implements Map<K, V> {

    private final int maxSize;

    public LRU(int initialCapacity, float loadFactor, int maxSize) {
        super(initialCapacity, loadFactor, true);
        this.maxSize = maxSize;
    }

    @Override
    protected boolean removeEldestEntry(Entry<K, V> eldest) {
        return  size() > maxSize;
    }

    public static void main(String[] args) {
        LRU<String, Integer> lru = new LRU<>(10, 1, 10);
        for (int i = 0 ; i < 10; i++){
            lru.put("index-" + i,i);
        }
        System.out.println(lru);
        lru.get("index-9");
        lru.get("index-8");
        lru.get("index-0");
        System.out.println(lru);
        lru.put("index-11", 11);
        System.out.println(lru);
    }
}

输出内容:

{index-0=0, index-1=1, index-2=2, index-3=3, index-4=4, index-5=5, index-6=6, index-7=7, index-8=8, index-9=9}
{index-1=1, index-2=2, index-3=3, index-4=4, index-5=5, index-6=6, index-7=7, index-9=9, index-8=8, index-0=0}
{index-2=2, index-3=3, index-4=4, index-5=5, index-6=6, index-7=7, index-9=9, index-8=8, index-0=0, index-11=11}

通过输出可以看到根据 LRU 思想移除掉了 index-1,基于 LinkedHashMap 的 LRU 容器始终保持最大容量 10

posted @ 2020-08-02 15:37  Haoyo  阅读(246)  评论(0)    收藏  举报