date: 2020-07-09 13:52:00

updated: 2020-07-21 17:40:00

LinkedHashMap 实现LRU缓存

参考

LinkedHashMap是HashMap的子类,但是内部还有一个双向链表维护键值对的顺序,每个键值对既位于哈希表中,也位于双向链表中。LinkedHashMap支持两种顺序插入顺序 、 访问顺序

插入顺序:先添加的在前面,后添加的在后面。修改操作不影响顺序

访问顺序:所谓访问指的是get/put操作,对一个键执行get/put操作后,其对应的键值对会移动到链表末尾,所以最末尾的是最近访问的,最开始的是最久没有被访问的,这就是访问顺序。

public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) 其中参数accessOrder就是用来指定是否按访问顺序,如果为true,就是访问顺序。

LRU(Least Recently Used): 最近最少使用

  1. public class LRUCache<K, V> extends LinkedHashMap<K, V> {
  2. private int maxEntries;
  3. public LRUCache(int maxEntries) {
  4. super(16, 0.75f, true);
  5. this.maxEntries = maxEntries;
  6. }
  7. @Override
  8. protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
  9. return size() > maxEntries;
  10. }
  11. }

在LinkedHashMap添加元素后,会调用removeEldestEntry防范,传递的参数时最久没有被访问的键值对,如果方法返回true,这个最久的键值对就会被删除。LinkedHashMap中的实现总返回false,该子类重写后即可实现对容量的控制。

  1. LRUCache<String,Object> cache = new LRUCache<>(3);
  2. cache.put("a","abstract");
  3. cache.put("b","basic");
  4. cache.put("c","call");
  5. cache.get("a");
  6. cache.put("d","滴滴滴");
  7. System.out.println(cache); // 输出为:{c=call, a=abstract, d=滴滴滴}

相比HashMap,LinkedHashMap还实现了三个方法,当且仅当 accessOrder=True 时会被调用到

  1. void afterNodeAccess(Node<K,V> p) { } //访问节点之后调用的方法
  2. void afterNodeInsertion(boolean evict) { } //插入节点之后调用的方法
  3. void afterNodeRemoval(Node<K,V> p) { } //删除节点之后调用的方法
  1. get()方法中调用afterNodeAccess()方法,具体作用是:在对节点进行访问之后,会更新链表,将节点移动到链表的尾部,表示最近被访问过。
  2. void afterNodeAccess(Node<K,V> e) { // move node to last
  3. LinkedHashMap.Entry<K,V> last;
  4. if (accessOrder && (last = tail) != e) {
  5. LinkedHashMap.Entry<K,V> p =
  6. (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
  7. p.after = null;
  8. if (b == null)
  9. head = a;
  10. else
  11. b.after = a;
  12. if (a != null)
  13. a.before = b;
  14. else
  15. last = b;
  16. if (last == null)
  17. head = p;
  18. else {
  19. p.before = last;
  20. last.after = p;
  21. }
  22. tail = p;
  23. ++modCount;
  24. }
  25. }
  1. LinkedHashMapput()是调用的父类HashMapput()方法
  2. 这个方法是在HashMap中的put()方法中被调用,在LinkedHashMap中被实现,具体作用是:在插入新节点后,因为缓存不够,需要删除最近最少使用的节点。要成功调用这个方法,还需要用户覆写 removeEldestEntry(first) 方法
  3. void afterNodeInsertion(boolean evict) { // possibly remove eldest
  4. LinkedHashMap.Entry<K,V> first;
  5. if (evict && (first = head) != null && removeEldestEntry(first)) {
  6. K key = first.key;
  7. removeNode(hash(key), key, null, false, true);
  8. }
  9. }
  1. LinkedHashMap成功调用removeNode()方法,删除节点之后,会调用本方法
  2. 具体作用是:在removeNode方法中,只是删除了HashMap中的节点,并没有在链表中删除。所以在removeNode中,回调了这个方法,将该节点从链表中删除(这里是删除的头结点,因为头结点是最早进入或者最近最久未使用的)。
  3. void afterNodeRemoval(Node<K,V> e) { // unlink
  4. LinkedHashMap.Entry<K,V> p =
  5. (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
  6. p.before = p.after = null;
  7. if (b == null)
  8. head = a;
  9. else
  10. b.after = a;
  11. if (a == null)
  12. tail = b;
  13. else
  14. a.before = b;
  15. }

LinkedHashMap 实现LRU缓存的更多相关文章

  1. 总是套路留人心, JAVA提供的套路: LinkedHashMap实现LRU缓存; InvocationHandler实现动态代理; fork/join实现窃取算法

    1. LinkedHashMap实现LRU缓存 LRU缓存核心是根据访问顺序排序, 自动移除队尾缓存, LinkedHashMap已经实现了这些要求: public LRUCache<K, V& ...

  2. 如何用LinkedHashMap实现LRU缓存算法

    阿里巴巴笔试考到了LRU,一激动忘了怎么回事了..准备不充分啊.. 缓存这个东西就是为了提高运行速度的,由于缓存是在寸土寸金的内存里面,不是在硬盘里面,所以容量是很有限的.LRU这个算法就是把最近一次 ...

  3. Java集合详解5:深入理解LinkedHashMap和LRU缓存

    今天我们来深入探索一下LinkedHashMap的底层原理,并且使用linkedhashmap来实现LRU缓存. 摘要: HashMap和双向链表合二为一即是LinkedHashMap.所谓Linke ...

  4. come on! 基于LinkedHashMap实现LRU缓存

    /** * @Description 基于LinkedHashMap实现一个基于'LRU最近最少使用'算法的缓存,并且最多存MAX个值 * @Author afei * @date:2021/4/25 ...

  5. LinkedHashMap实现LRU缓存算法

    LinkedHashMap的get()方法除了返回元素之外还可以把被访问的元素放到链表的底端,这样一来每次顶端的元素就是remove的元素. 构造函数如下: public LinkedHashMap  ...

  6. 转:LinkedHashMap使用(可以用来实现LRU缓存)

    1. LinkedHashMap概述: LinkedHashMap是HashMap的一个子类,它保留插入的顺序,如果需要输出的顺序和输入时的相同,那么就选用LinkedHashMap. LinkedH ...

  7. LRU缓存实现(Java)

    LRU Cache的LinkedHashMap实现 LRU Cache的链表+HashMap实现 LinkedHashMap的FIFO实现 调用示例 LRU是Least Recently Used 的 ...

  8. [转]LRU缓存实现(Java)

    LRU Cache的LinkedHashMap实现 LRU Cache的链表+HashMap实现 LinkedHashMap的FIFO实现 调用示例 LRU是Least Recently Used 的 ...

  9. LRU缓存实现

    LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高” 在java中可以采用Linke ...

随机推荐

  1. volatile关键字解释和使用

    一.java内存模型的相关概念:原子性.可见性与有序性 原子性: 原子是世界上的最小单位,具有不可分割性.比如 a=0:(a非long和double类型) 这个操作是不可分割的,那么我们说这个操作时原 ...

  2. PHP绕过disable_function

    PHP绕过disable_function 常规绕过 exec exec执行command命令,但是不会输出全部结果,而是返回结果的最后一行. 想得到全部的结果,可以使用第二个参数,让其输出到一个数组 ...

  3. 基础篇:深入JMM内存模型解析volatile、synchronized的内存语义

    目录 1 java内存模型,JMM(JAVA Memory Model) 2 CPU高速缓存.MESI协议 3 指令重排序和内存屏障指令 4 happen-before原则 5 synchronize ...

  4. C1853 编译器错误:fatal error C1853: 'pjtname.pch' precompiled header file is from a previous

    转载:https://www.cnblogs.com/emanlee/archive/2010/10/16/1852998.html 用VC++ 2008 编写C语言程序,编译出现错误: 预编译头文件 ...

  5. STM32F103C8T6驱动WS2812b灯条

    STM32F103C8T6驱动WS2812b灯条 几天小朋友到别人家玩,看上了人家的金鱼,人家就给了她一条小金鱼,有了小金鱼,怕它没氧气挂掉,买了一个氧气泵,没有东西喂它也不行,又买了一包鱼料,又因为 ...

  6. Vue路由History模式分析

    Vue路由History模式分析 Vue-router是Vue的核心组件,主要是作为Vue的路由管理器,Vue-router默认hash模式,通过引入Vue-router对象模块时配置mode属性可以 ...

  7. minimist

    下载 minimistminimist 解析参数选项 这个模块是乐观主义者参数解析器的核心,没有所有的 奇特的装饰. 例子 var argv = require('minimist')(process ...

  8. 每日一题 LeetCode 486. 预测赢家 【递推】【前缀和】【动态规划】

    题目链接 https://leetcode-cn.com/problems/predict-the-winner/ 题目说明 题解 主要方法:递推:动态规划:前缀和 解释说明: 求前缀和 pre_nu ...

  9. LVS搭建

    LVS集群搭建 NAT架构图 1.在RS188,RS189操作 #安装httpd服务[root@t1 ~]# yum install -y httpd[root@t1 ~]# echo "I ...

  10. 【Jenkins】远程调用jenkins进行构建方式!

    前提:jenkins支持远程调用(具体设置自行百度)1.在我的个人中心--configure--API TOKEN--如果没有,则添加一个token,并生成,再复制并记录下来2.在你的job上面加上你 ...