removeeldestentry 不生效的根本原因是未正确配置 linkedhashmap 的构造参数——必须使用三参数构造函数指定初始容量、负载因子和 accessorder=false,并设置容量上限,否则淘汰逻辑不会触发。

为什么 removeEldestEntry 不生效?
多数人写完重写方法却没触发淘汰,根本原因是没开启“自动删除”开关——LinkedHashMap 默认不淘汰任何元素,哪怕你写了 removeEldestEntry,也得靠构造时传入 accessOrder = false(默认值)+ 容量限制才能激活它。
常见错误现象:put 一堆数据后,size() 持续增长,removeEldestEntry 根本没被调用。
- 必须用带
initialCapacity、loadFactor和accessOrder的三参数构造函数,且accessOrder要为false(FIFO 依赖插入序,不是访问序) -
removeEldestEntry只在每次put或putAll后被调用一次,不是定时触发,也不是在get时调用 - 如果 map 没设初始容量上限(比如只传了
16但没控制最大 size),扩容机制会先起作用,淘汰逻辑压根不启动
怎么让 FIFO 容量限制真正生效?
关键不在重写方法本身,而在“谁来决定删不删”——removeEldestEntry 返回 true 才删最老 entry,但它只在 put 引发 size 超限时才有机会执行。所以必须把“容量上限”和“判断逻辑”对齐。
使用场景:实现固定大小的缓存(如最近 100 条日志)、滑动窗口计数、简单 LRU 变体(但注意:这不是 LRU,是 FIFO)。
- 构造时指定合理初始容量,避免频繁扩容干扰淘汰节奏,例如:
new LinkedHashMap(128, 0.75f, false) - 在
removeEldestEntry里直接比较size() > MAX_SIZE,不要用entrySet().size()(冗余) - 别在重写方法里做耗时操作(如 IO、锁),它在
put路径上同步执行,会拖慢所有写入
示例:
private static final int MAX_SIZE = 100;<br>Map<String, Object> cache = new LinkedHashMap<>(128, 0.75f, false) {<br> @Override<br> protected boolean removeEldestEntry(Map.Entry<String, Object> eldest) {<br> return size() > MAX_SIZE;<br> }<br>};
accessOrder = true 会导致 FIFO 失效吗?
会,而且很彻底。一旦设成 true,LinkedHashMap 就按访问顺序重排链表,最老 entry 变成“最久未访问”的那个,不再是“最先插入”的那个——这直接把 FIFO 变成了 LRU 底层行为。
性能影响:开启 accessOrder 后,每次 get 都要挪动节点位置,带来额外的链表操作开销;而 FIFO 场景下 get 理应零成本重排。
- FIFO 场景必须保持
accessOrder = false(这也是构造函数第三个参数的默认值) - 如果误设为
true,你会发现removeEldestEntry删掉的不是最早put的项,而是最冷门的项 - 没有中间态:不能靠
get触发淘汰,也不能靠put+accessOrder=true模拟 FIFO
容易被忽略的线程安全问题
LinkedHashMap 本身不保证线程安全,而 removeEldestEntry 的触发时机又紧贴 put 内部逻辑,多线程并发 put 可能导致 size 判断错乱、重复删除或漏删。
常见错误现象:缓存 size 波动异常、偶现 ConcurrentModificationException(尤其在遍历时被淘汰干扰)、部分 entry 意外丢失。
- 不要给裸
LinkedHashMap加读写锁再用,开销大且易出死锁;优先考虑java.util.concurrent.ConcurrentHashMap+ 外部淘汰逻辑 - 如果坚持用
LinkedHashMap,至少用Collections.synchronizedMap包一层,但注意:它只同步单个方法,size()和put()之间仍有竞态 - 更稳妥的做法是封装成一个线程安全的
FifoCache类,在内部用ReentrantLock控制整个put+ 判断 + 删除流程原子化
事情说清了就结束:FIFO 不是靠“重写了方法”就自动跑起来的,它依赖构造参数、触发时机、线程上下文三者咬合。漏掉任意一环,缓存就只是个不会丢数据的普通 map。










