用LinkedHashMap实现LRU缓存需设accessOrder=true启用访问顺序,并重写removeEldestEntry控制淘汰;其线程不安全,高并发需额外同步或换用Caffeine等库。

用 LinkedHashMap 实现 LRU 缓存,核心就两点:让链表按访问顺序排列,并在容量超限时自动剔除最久未用的项。Java 已经把底层机制准备好了,你只需做轻量定制。
关键参数 accessOrder 必须设为 true
默认情况下,LinkedHashMap 按插入顺序维护节点(accessOrder = false),这不符合 LRU 要求。必须在构造时传入 true,启用访问顺序模式:
- 每次
get()或put()已存在 key 时,对应节点会被移到链表尾部 - 链表头部始终是最久未被访问的节点,正好是淘汰目标
- 示例写法:
new LinkedHashMap<K,V>(initCap, 0.75f, true)
重写 removeEldestEntry 控制淘汰逻辑
这个方法在每次 put() 后被自动调用,返回 true 就会删除链表头节点(即最老项)。只需判断当前 size 是否超过预设容量:
- 定义一个
capacity字段保存最大条目数 @Override protected boolean removeEldestEntry(Map.Entry<K,V> eldest) { return size() > capacity; }- 注意:该方法只在
put时触发,get不会主动触发淘汰,但会更新节点位置
注意线程安全问题
LinkedHashMap 本身不是线程安全的,多线程环境下直接使用可能出错:
- 简单场景可用
Collections.synchronizedMap(new LRUCache(...))包装 - 但同步包装仅保证单个操作原子性,遍历时仍需手动加锁或转为不可变快照
- 高并发建议改用
ConcurrentHashMap+ 显式双链表,或直接使用caffeine等成熟缓存库
完整可运行示例
以下是一个精简可靠的实现:
class LRUCache<K, V> extends LinkedHashMap<K, V> {
private final int capacity;
public LRUCache(int capacity) {
// 初始容量、负载因子、启用访问顺序
super(capacity, 0.75f, true);
this.capacity = capacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > capacity;
}
}
使用时:LRUCache<String, Integer> cache = new LRUCache<>(3);,后续 put 和 get 即自动具备 LRU 行为。

















