如何在 Java 中使用 LinkedHashMap 的访问顺序模式实现一个基础的 LRU 缓存淘汰
LinkedHashMap设置accessOrder=true后,每次访问将节点移至尾部,链表头部即为最久未用条目。通过继承并重写removeEldestEntry()方法,依据size()>capacity自动淘汰。该实现非线程安全,并发场景需加锁或改用ConcurrentHashMap。不建议存储null值,避免get()返回null时无法区分未命中与空
这部分内容,其实谈到底层原理并不复杂,但能把它用好、用对,才是日常开发中拉开差距的地方。就拿 accessOrder=true 这个参数来说,很多开发者知道它能实现LRU,但真要写一个健壮的缓存,里头门道不少。我们一个一个拆开看。

为什么 LinkedHashMap 的 accessOrder=true 能支持 LRU
原因很简单。你构造 LinkedHashMap时,把第三个参数设为 true,它内部那条维护顺序的双向链表就不再看“谁先来”,而是看“谁最后被用”。每次你调用 get() 或者 put()(如果是更新已有key),它都会默默把那个节点挪到链表尾部。
这样一来,链表头部就永远蹲着那个“最久没被翻过牌子”的条目。淘汰时,你只需要把头节点干掉就行,效率很高。
需要留意的是,单纯新增一个key时,它只是追加到尾部,不会打乱其他节点的相对顺序。这其中的区别,你写代码的时候得想清楚。
如何重写 removeEldestEntry() 控制缓存容量
容量上限怎么控制?靠一个钩子方法——removeEldestEntry()。它每次 put() 结束后被自动调用,如果返回 true,框架就顺手把链表头(也就是最老的节点)删掉。这是实现容量限制的核心,不是你手动去轮询或者定时清理的。
关键点在于:
- 你必须继承
LinkedHashMap然后重写这个方法,直接new出来的实例没法改。 - 判断逻辑通常就一行:
size() > capacity,别在里面写日志、搞IO这些耗时操作,会拖累性能。 - 这个方法在
put()内部是同步执行的,你不用额外加锁,但整个缓存仍然需要考虑并发安全。
class LRUCacheextends LinkedHashMap { private final int capacity; LRUCache(int capacity) { // accessOrder = true super(capacity, 0.75f, true); this.capacity = capacity; } @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > capacity; } }
并发场景下直接用 LinkedHashMap 子类会出什么问题
很多人在这块栽过跟头。LinkedHashMap 本身可不是线程安全的。多线程环境下同时搞 get() 和 put(),链表结构会乱套,甚至死循环(JDK 7/8 时代有经典bug),或者直接抛 ConcurrentModificationException。
为了防杠,有人会直接加个 synchronized,但这招在“读多写少”的场景下直接让你的吞吐量惨不忍睹。用 Collections.synchronizedMap() 包一下呢?有个坑——removeEldestEntry() 并不在同步块里,可能会失效。
更稳妥的做法是:自己拿 ReentrantLock 手动锁住 get() 和 put() 的临界区。当然,如果你愿意放弃 LinkedHashMap 方案,直接用 ConcurrentHashMap 加上自定义的队列,也是条路。
别忽略 get() 返回 null 时的边界行为
缓存里没有key的时候,get() 返回 null,这不会触发链表调整,符合预期。但容易被忽略的是:put(key, null) 是合法的,它会正常参与LRU排序。如果业务允许value为 null,那么 get() 返回 null 时,你就分不清是“没命中”还是“命中了但值为null”。
建议是:
- 最好别存
nullvalue。可以在put()前做校验,发现null就直接抛NullPointerException。 - 如果非支持不可,可以考虑用
Optional包装返回值,或者额外维护一个Set来记录哪些key已经存在。 computeIfAbsent()这类衍生方法在 accessOrder 模式下同样会触发重排序,但你得小心lambda内部的递归调用,别把自己玩死了。
说到底,accessOrder 模式只是一个高效的链表维护策略,它不帮你解决原子性、可见性、null 语义这些上层问题。它只优雅地做到了:帮你轻松判定“哪个是最近最久没被碰过的”。
Visual Studio Code 是微软提供的免费代码编辑器,支持 macOS,并为 Intel 与 Apple 芯片 Mac 提供适配版本。软件集代码编辑、调试、Git 源代码管理、集成终端和扩展市场于一体。
Photoshop 2026 是 Adobe 推出的专业图像处理与视觉设计软件,支持 Windows、macOS 和 iPad 等平台,广泛应用于摄影修图、电商设计、平面海报、数字绘画及视觉合成等创作场景。
Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。
Photoshop 2026 是 Adobe 推出的专业图像处理与视觉设计软件,支持 Windows、macOS 和 iPad 等平台,广泛应用于摄影修图、电商设计、平面海报、数字绘画及视觉合成等创作场景。
Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。














