必须用linkedhashmap而非hashmap的场景是需要遍历顺序与插入顺序严格一致时,如日志聚合、配置加载、api响应保序;其轻量且支持o(1)查找/插入,而treemap开销大,hashmap顺序不可靠。
什么时候必须用 LinkedHashMap 而不是 HashMap
当你需要遍历顺序和插入顺序严格一致时,LinkedHashMap 是唯一轻量级解法。比如日志聚合、配置项加载、API响应字段保序——这些场景里,前端或下游系统依赖“先写哪个 key,就先看到哪个 value”,而 HashMap 的遍历结果是不可预测的(哪怕当前运行看起来有序,换 JDK 版本或数据量就可能乱)。
- 插入顺序敏感:读取 properties/yaml 配置后按原始顺序序列化回 JSON,避免字段错位
- 调试友好:打印 map 时能一眼看出操作时序,不用反复查日志确认执行路径
- 不接受 TreeMap 的开销:TreeMap 虽然有序,但所有操作都是 O(log n),而
LinkedHashMap查找/插入仍接近 O(1)
accessOrder = true 真正管用的 LRU 缓存怎么写
很多人以为设了 new LinkedHashMap(16, 0.75f, true) 就自动是 LRU,其实漏了关键一步:removeEldestEntry 必须重写,否则容量无限增长。
- 只设
accessOrder = true只会让 get/put 已存在 key 时把 entry 移到链表尾,但不会删老数据 - 必须继承并重写
removeEldestEntry,返回size() > MAX_SIZE才触发淘汰 - 注意:
put新 key 和get已有 key 都算“访问”,都会触达链表尾部,这才是 LRU 的核心逻辑
class LRUCache<K, V> extends LinkedHashMap<K, V> {
private final int capacity;
LRUCache(int capacity) {
super(capacity, 0.75f, true);
this.capacity = capacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > capacity; // 关键:不写这行,永远不淘汰
}
}
多线程环境下直接用 LinkedHashMap 会出什么问题
它和 HashMap 一样非线程安全,但问题更隐蔽:除了常见的 ConcurrentModificationException,还可能因链表指针错乱导致遍历时跳过元素、死循环,甚至 JVM 挂起。