跳转到主内容
极星编程网:以代码为星,赴技术山海!

怎么通过 LinkedHashMap 的 removeEldestEntry() 方法定制数组缓存的自动淘汰策略

removeEldestEntry() 是 LinkedHashMap 实现缓存淘汰的核心钩子方法,每次 put/putAll 后调用,返回 true 时自动删除头节点;默认按插入顺序淘汰最老项,启用 accessOrder=true 可实现 LRU;适用于固定容量 FIFO 或结合时间/频次的自定义策略,但不主动轮询、非线程安全。 linkedhashmap 的
removeeldestentry()
方法是实现自定义缓存淘汰策略的核心机制,它在每次插入新元素后被调用,返回
true
时会自动删除最老(即最先插入)的条目。关键在于重写该方法,结合业务需求判断是否触发淘汰。 理解 removeEldestEntry() 的触发时机和作用 该方法不是在插入前检查,而是在
put()
或
putAll()
完成后、返回前被调用,参数是当前即将成为“最老”的那个 Entry(即链表头节点)。它不负责删除动作本身,只决定“要不要删”——返回
true
才会由 LinkedHashMap 自动移除头节点。 注意:只有在构造 LinkedHashMap 时启用访问顺序(
accessOrder = true
)才会按访问时间排序;若保持插入顺序(默认),则淘汰的是最早插入的项。 实现固定容量的 FIFO 缓存 这是最常见用法:限制缓存最大条目数,超出即淘汰最老项。 创建 LinkedHashMap 时传入初始容量、加载因子,并设
accessOrder = false
(默认) 重写
removeEldestEntry()
,判断
size() > maxSize
示例代码:
int maxSize = 100; Map cache = new LinkedHashMap<>(16, 0.75f, false) { @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > maxSize; } };
基于时间或使用频率的进阶策略 单纯靠 size 不够灵活,可扩展 Entry 类型或借助外部结构记录元数据: LRU(最近最少使用) :启用
accessOrder = true
,配合 size 限制即可,无需额外时间戳 带过期时间的缓存 :不能仅靠
removeEldestEntry()
实现定时过期(它不主动轮询),但可在该方法中检查 eldest 的插入/访问时间戳,如:
return System.currentTimeMillis() - eldest.timestamp > 60_000;
按访问频次淘汰 :需自行维护计数器(如用
AtomicInteger
包装 value),在
get()
中更新,在
removeEldestEntry()
中比较频次阈值 注意事项与避坑点 该机制是被动触发,依赖写操作驱动,不适合强时效性场景(比如必须精确到秒过期);也不支持并发安全,默认非线程安全,高并发下需包装为
Collections.synchronizedMap()
或改用
ConcurrentHashMap
配合显式淘汰逻辑。 另外,重写时避免在方法内修改 map 状态(如调用
remove()
),可能引发
ConcurrentModificationException
或死循环。

相关文章