java中实现lru缓存淘汰算法最推荐方式是继承linkedhashmap并设置accessorder=true,重写removeeldestentry方法判断size()>maxsize,时间复杂度o(1),避免手写链表的复杂性与线程安全风险。

Java 中实现 LRU 缓存淘汰算法,核心是维护“最近访问顺序”,并在容量超限时自动移除最久未使用的条目。最实用、最推荐的方式不是从零手写 HashMap + 双向链表,而是**直接基于 LinkedHashMap 的访问顺序特性来封装**——它底层已用哈希表 + 双向链表实现,且支持 O(1) 的 get/put 和自动排序。
用 LinkedHashMap 继承方式快速实现
这是生产环境首选方案,代码简洁、稳定、不易出错:
- 构造时必须传 accessOrder = true,否则按插入顺序排列,不是 LRU
- 重写 removeEldestEntry 方法,只判断当前 size 是否超过最大容量
- 注意:put 后 size 已 +1,所以条件写
size() > maxSize,不是>= - 该方法在每次 put 或 putAll 成功后触发,由父类自动执行删除,无需手动操作链表
关键代码示例
以下是一个可直接运行的泛型实现:
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
public class LRUCache<k v> extends LinkedHashMap<k v> {
private final int maxSize;
public LRUCache(int maxSize) {
// 初始容量16,负载因子0.75,accessOrder=true → 按访问顺序排列
super(16, 0.75f, true);
this.maxSize = maxSize;
}
@Override
protected boolean removeEldestEntry(Map.Entry<k v> eldest) {
return size() > maxSize; // 超过容量即淘汰最老(即最久未访问)项
}
}</k></k></k>
为什么不用手写 HashMap + 双向链表?
虽然教科书常讲“哈希表查节点 + 双向链表调顺序”,但实际开发中需权衡:
- 手写要处理节点增删、头尾指针更新、空指针、并发安全等细节,易引入 bug
- LinkedHashMap 已将这些封装好,且经过 JDK 长期验证,性能和稳定性更优
- 如需扩展功能(如过期时间、加载回调、统计命中率),建议在此基础上装饰,而非替换底层
- 只有在特殊场景(如需精确控制内存布局、做 JNI 优化或学习目的)才推荐手写
线程安全要额外处理
LinkedHashMap 本身不是线程安全的,子类也不会自动变安全:
- 多线程并发 put 可能导致
ConcurrentModificationException或 size 判断失准 - 简单方案:用
Collections.synchronizedMap(new LRUCache(...)),但会串行化所有操作 - 高并发场景建议改用 Caffeine 或 Guava Cache,它们内置了分段锁、异步淘汰、权重驱逐等工业级能力
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










