直接用linkedhashmap实现高并发缓存不可行——它本身线程不安全;可行方案是继承linkedhashmap并用reentrantreadwritelock封装读写操作,构造时设accessorder=true,重写removeeldestentry仅判断size()>capacity。

直接用 LinkedHashMap 实现高并发缓存不可行——它本身线程不安全,不能裸用。但可以“基于它快速手写”一个线程安全的 LRU 缓存,关键不是改 LinkedHashMap,而是加一层轻量同步控制。
核心思路:继承 + 读写锁封装
不重造轮子,也不用全局 synchronized(性能差),而是用 ReentrantReadWriteLock 分离读写路径:
- 读操作(
get)用读锁,允许多个线程并发访问 - 写操作(
put、clear)用写锁,独占执行 - 构造时必须传
accessOrder = true,否则访问不会更新顺序 -
removeEldestEntry只需一行:return size() > capacity;,别写>=或调用其他 map 方法
关键代码结构(泛型安全版)
以下是最小可用骨架,已规避常见坑:
public class LRUCache<k v> extends LinkedHashMap<k v> {
private final int capacity;
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock readLock = lock.readLock();
private final Lock writeLock = lock.writeLock();
public LRUCache(int capacity) {
// 初始容量设为 capacity+1,避免刚满就触发扩容;负载因子 0.75f 是平衡选择
super(capacity + 1, 0.75f, true);
this.capacity = capacity;
}
@Override
public V get(Object key) {
readLock.lock();
try {
return super.get(key);
} finally {
readLock.unlock();
}
}
@Override
public V put(K key, V value) {
writeLock.lock();
try {
return super.put(key, value);
} finally {
writeLock.unlock();
}
}
@Override
protected boolean removeEldestEntry(Map.Entry<k v> eldest) {
return size() > capacity;
}
}</k></k></k>
为什么这算“快速手写”而非“生产级”?
它满足了“高并发下基本可用”,但仍有明显边界:
- 不支持统计(命中率、淘汰数)、过期(TTL)、异步淘汰回调等增强功能
- 读写锁粒度仍是整个 map,极端高并发下可能成瓶颈(比如每秒数万 put)
- 没处理 null key/value 的策略(可按需在 put/get 中加判空)
- 若 value 是大对象或长生命周期对象,需考虑用
WeakReference<v></v>防内存泄漏
上线前必做两件事
否则缓存逻辑可能完全失效:
- 验证访问顺序是否生效:插入 A/B/C(容量=2)→ get(A) → put(D),检查 B 是否被剔除、A 是否在尾部
-
压测读写混合场景:用 JMeter 或 JUnit + CountDownLatch 模拟 100 线程并发 get/put,确认无
ConcurrentModificationException或数据丢失
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











