LinkedHashMap 实现 LRU 缓存需启用 accessOrder=true 并重写 removeEldestEntry();get/put(更新)移动节点至尾部,put(新键)触发淘汰检查,仅插入新数据可能淘汰头节点。

LinkedHashMap 实现 LRU 缓存淘汰,关键就两点:启用访问顺序模式 + 重写 removeEldestEntry() 方法。它不是靠额外线程或定时任务,而是利用自身链表结构和插入/访问时的节点移动机制,在 O(1) 时间内完成“最近使用”排序和自动淘汰。
必须开启 accessOrder = true
默认 LinkedHashMap 按插入顺序排列,这对 LRU 没用。要让“最近访问的排在最后、最久未用的留在最前”,构造时第三个参数必须传 true:
new LinkedHashMap<String, Object>(16, 0.75f, true)- 这样每次
get(key)或put(key, value)(更新已有 key)时,对应节点会自动移到链表尾部 - 链表头部始终是“最久未被访问”的 entry,正好作为淘汰目标
重写 removeEldestEntry() 控制淘汰时机
这个方法是 LinkedHashMap 提供的钩子,只在每次 put() 或 putAll() 执行完后调用,不用于 get()。它接收当前链表头节点(即最老项)作为参数,返回 true 就自动删掉它:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 典型写法是判断当前 size 是否超过容量阈值:
return size() > 100; - 注意:它只检查 size,不检查时间或频次;如需 TTL(过期时间),得自己在 value 中存时间戳,并在 put/get 里额外判断
- 不要在该方法里调用
remove()或修改 map,否则可能抛ConcurrentModificationException
LRU 行为的实际表现
理解哪些操作真正驱动淘汰,能避免误用:
立即学习“Java免费学习笔记(深入)”;
-
put(新 key)→ 插入尾部 + 触发removeEldestEntry()→ 可能淘汰头节点 -
put(已有 key)→ 移动该节点到尾部 + 触发淘汰检查(但 size 不变,通常不淘汰) -
get(key)→ 移动该节点到尾部,但不触发淘汰检查;纯读不会减少缓存条目数 - 所以,只有插入新数据或扩容时才可能触发清理,纯高频读不会导致缓存收缩
封装成可复用的缓存类
推荐继承 LinkedHashMap 并封装容量控制逻辑,更清晰安全:
- 把最大容量设为 final 字段或通过构造函数传入
- 重写
removeEldestEntry()时直接对比size() > capacity - 如需线程安全,外部加
Collections.synchronizedMap(),或改用ConcurrentHashMap + 显式双向链表(LinkedHashMap 本身非线程安全)

















