LRU_Cache

作者: Weechan_ | 来源:发表于2019-02-13 17:53 被阅读0次

LRU(Least Recently Used) 表示最近最少使用

LinkedHashMap

LRU内部维护的是一个LInkedHashMap,因此先从LinkedHashMap看起

LinkedHashMap与HashMap的区别:
LinkedHashMap保持了元素的插入顺序,使得遍历顺序可按插入顺序输出

盗图来查看LinkedHashMap的内部结构

image.png

说白了就是每个结点即是HashMap里每个桶的结点也是一条双向链表里的结点。
而LinkedHashMap依靠该双向链表保存着插入的顺序

这三个方法是HashMap预留给LinkedhashMap的接口,

// Callbacks to allow LinkedHashMap post-actions
void afterNodeAccess(Node<K,V>  p) {}  // 1 
void afterNodeInsertion(boolean evict) {}  // 2
void afterNodeRemoval(Node<K,V> p) {} // 3

首先看afterNodeAccess,当为accessOrder的时候,就把结点放到末尾

void afterNodeAccess(Node<K,V> e) { // move node to last
        LinkedHashMapEntry<K,V> last;
        if (accessOrder && (last = tail) != e) {
            LinkedHashMapEntry<K,V> p =
                (LinkedHashMapEntry<K,V>)e, b = p.before, a = p.after;
            // 省略一堆指针的操作,就是将读取到的结点e 放到链表末尾
            ++modCount;
        }
    }

afterNodeInsertion 参数evict 必为true
若用户定义了removeEldestEntry 就会在哈希表中移除链表的表头元素,而removeEldestEntry默认返回false

    void afterNodeInsertion(boolean evict) { // possibly remove eldest
        LinkedHashMapEntry<K,V> first;
        if (evict && (first = head) != null && removeEldestEntry(first)) {
            K key = first.key;
            removeNode(hash(key), key, null, false, true);
        }
    }

afterNodeRemoval() 用于从链表中删除结点

    void afterNodeRemoval(Node<K,V> e) { // unlink
       //省略,其实也是指针操作,从链表中删除该结点
    }

LinkedHashMap对put操作没有重写,而对get的定义如下

    public V get(Object key) {
        Node<K,V> e;
        if ((e = getNode(hash(key), key)) == null)
            return null;
        if (accessOrder)
            afterNodeAccess(e);
        return e.value;
    }

可以看到如果为accessOrder的时候就执行afterNodeAccess();

因此当LinkedHashMap设置成accessOrder并定义removeEldestEntry,
该双向链表的特性不就是刚被访问过的结点将在链表表尾,
插入的时候可根据removeEldestEntry决定是否要删除表头元素。
因此很适合构建LRU缓存

LRU_Cache

image.png

LruCache的构造函数如图,可见他将accessOrder设置成TRUE了。
然而LruCache并没有使用removeEldestEntry的返回值来决定是否删除元素。而是使用trimToSize方法删除超出lrucache大小的最旧的元素。

在每次put的时候会调用trimToSize来保证大小小于maxSize

    private void trimToSize(int maxSize) {
        while (true) {
            K key;
            V value;
            synchronized (this) {
                if (size <= maxSize) {
                    break;
                }
                 Map.Entry<K, V> toEvict = map.eldest();
                for (Map.Entry<K, V> entry : map.entrySet()) {
                    toEvict = entry;
                }
                // END LAYOUTLIB CHANGE
                if (toEvict == null) {
                    break;
                }
                key = toEvict.getKey();
                value = toEvict.getValue();
                map.remove(key);
                size -= safeSizeOf(key, value);
                evictionCount++;
            }
            entryRemoved(true, key, value, null);
        }
    }

相关文章

  • LRU_Cache

    LRU(Least Recently Used) 表示最近最少使用 LinkedHashMap LRU内部维护的是...

  • 笔记2——编辑距离 Edit Distance

    lru_cache模块 functools.lru_cache 是装饰器,它实现了备忘(memoization)功...

  • python内置缓存lru_cache

    lru_cache LRU算法原理 LRU (Least Recently Used,最近最少使用) 算法是一种缓...

  • 偏函数partial

    Python的内置模块functiontools为解决实际问题提供了便捷的方法,如下所示 其中lru_cache,...

  • 斐波那契数列

    方法一:不导入任何帮助模块计算数列 方法二:导入functools模块下的lru_cache方法计算数列

  • lru_cache装饰器的作用

    python lru_cache装饰器的作用 ru_cache装饰器实现了备忘功能,能够优化函数执行速度,他把耗时...

  • python nonlocal的理解使用

    nonlocal 可以将一个变量声明为非本地变量, 在python的lru_cache看到了使用 实例中, 当a变...

  • 实用装饰器 lru_cache

    python 的functools 提供了许多实用的工具,lru_cache是经常用到的一种。它的作用是缓存该函数...

  • lru_cache的简单实现

    主要代码出处,轮子就自己不造了,就做一些简单的修改。感谢源代码作者。

  • 说说 Python 的 lru_cache 装饰器

    Python 的 lru_cache 装饰器是一个为自定义函数提供缓存功能的装饰器。其内部会在下次以相同参数调用该...

网友评论

      本文标题:LRU_Cache

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