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; } - 注意:它不适用于
putIfAbsent等非覆盖式写入(Java 8+),因为这些方法内部不触发removeEldestEntry;如需严格容量控制,应统一使用put() - 也可结合时间判断(如淘汰超过 5 分钟未访问的项),但需自行记录时间戳,会失去纯
LinkedHashMap的简洁性
线程安全考虑
LinkedHashMap 本身非线程安全。若多线程并发读写,有几种实用方案:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 用
Collections.synchronizedMap(new LinkedHashMap(...))—— 简单但粒度粗(整个 map 锁),适合低并发场景 - 包装为
ConcurrentHashMap+ 手动 LRU 管理 —— 更复杂,失去本文的“快速构建”优势 - 推荐:若仅读多写少,且能接受短暂不一致,可加
volatile引用 + 读写锁(如ReentrantReadWriteLock),平衡性能与安全性
完整可运行示例
一个线程安全(读写锁)、容量限制为 3 的 LRU 缓存:
立即学习“Java免费学习笔记(深入)”;
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();
}
}
}
使用:LRUCache<string integer> cache = new LRUCache(3);</string>,插入 4 个不同 key 后,最先插入的那个会被自动淘汰。

















