linkedhashmap 是实现轻量级 lru 缓存最简洁高效的方式,通过构造时设置 accessorder=true 启用访问顺序,并重写 removeeldestentry() 控制容量;需注意线程安全问题,可结合 readwritelock 实现读写分离。
在 java 中,linkedhashmap 提供了天然的访问顺序支持和 removeeldestentry() 钩子方法,是实现轻量级 lru(least recently used)缓存最简洁、高效的方式之一——无需额外维护时间戳或队列,底层链表自动按访问/插入顺序组织节点。
启用访问顺序模式
默认情况下 LinkedHashMap 按插入顺序排列。要实现 LRU,必须在构造时将 accessOrder 参数设为 true:
new LinkedHashMap<k v>(initialCapacity, loadFactor, true)</k>- 设为
true后,每次get()或put()已存在 key 的操作,都会把对应节点移到链表尾部(即“最近使用”位置) - 链表头部始终是“最久未使用”的条目
重写 removeEldestEntry 控制容量
该方法在每次 put()(包括更新)后被调用,返回 true 则自动删除链表头部节点(即最老的 entry)。只需根据 size 判断是否超限:
- 例如限制缓存最多 100 个条目:
@Override protected boolean removeEldestEntry(Map.Entry<k v> eldest) { return size() > 100; }</k> - 注意:它不适用于
putIfAbsent等非覆盖式写入(Java 8+),因为这些方法内部不触发removeEldestEntry;如需严格容量控制,应统一使用put() - 也可结合时间判断(如淘汰超过 5 分钟未访问的项),但需自行记录时间戳,会失去纯
LinkedHashMap的简洁性
线程安全考虑
LinkedHashMap 本身非线程安全。若多线程并发读写,有几种实用方案:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
- 用
Collections.synchronizedMap(new LinkedHashMap(...))—— 简单但粒度粗(整个 map 锁),适合低并发场景 - 包装为
ConcurrentHashMap+ 手动 LRU 管理 —— 更复杂,失去本文的“快速构建”优势 - 推荐:若仅读多写少,且能接受短暂不一致,可加
volatile引用 + 读写锁(如ReentrantReadWriteLock),平衡性能与安全性
完整可运行示例
一个线程安全(读写锁)、容量限制为 3 的 LRU 缓存:
class LRUCache<k v> extends LinkedHashMap<k v> {
private final int capacity;
private final ReadWriteLock lock = new ReentrantReadWriteLock();
LRUCache(int capacity) {
super(16, 0.75f, true); // accessOrder = true
this.capacity = capacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry<k v> eldest) {
return size() > capacity;
}
@Override
public V get(Object key) {
lock.readLock().lock();
try {
return super.get(key);
} finally {
lock.readLock().unlock();
}
}
@Override
public V put(K key, V value) {
lock.writeLock().lock();
try {
return super.put(key, value);
} finally {
lock.writeLock().unlock();
}
}
}</k></k></k>
使用:LRUCache<string integer> cache = new LRUCache(3);</string>,插入 4 个不同 key 后,最先插入的那个会被自动淘汰。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










