1. LRU缓存算法核心原理
在计算机系统中,缓存技术无处不在。从CPU的多级缓存到浏览器的页面缓存,再到分布式系统中的Redis缓存,它们都面临一个共同问题:当缓存空间不足时,应该优先淘汰哪些数据?LRU(Least Recently Used)算法就是解决这个问题的经典方案。
1.1 为什么需要缓存淘汰策略
想象你有一个容量有限的背包(缓存),每次出门只能带有限数量的物品(数据)。你会如何选择要带的物品?最合理的做法是:
- 经常使用的物品(高频访问数据)始终放在包里
- 最近很少使用的物品(低频访问数据)可以暂时拿出
- 几乎不用的物品(冷数据)直接淘汰
这就是LRU算法的现实类比。在工程实践中,缓存淘汰策略直接影响系统性能:
- 数据库访问优化:MySQL的Query Cache、Redis的键淘汰策略
- 操作系统资源管理:内存页面置换算法
- CDN节点缓存:热点内容优先缓存
1.2 LRU的工作原理
LRU的核心思想可以用一个简单的例子说明:
假设缓存容量为3,访问顺序为:A → B → C → A → D
- 初始状态:[ ]
- 访问A后:[A]
- 访问B后:[B, A](最新访问在前)
- 访问C后:[C, B, A]
- 再次访问A:[A, C, B](A被提到最前)
- 访问D时缓存已满,淘汰最久未使用的B:[D, A, C]
这个例子展示了LRU的两个关键操作:
- 访问命中:将数据移动到"最近使用"位置
- 淘汰机制:当空间不足时移除"最久未使用"的数据
关键特性:LRU认为最近被访问过的数据,未来被再次访问的概率更高
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. LRU的手动实现方案
2.1 数据结构设计
要实现O(1)时间复杂度的LRU,需要组合使用两种数据结构:
- 双向链表:维护数据的访问顺序
- 链表头部表示最近访问
- 链表尾部表示最久未访问
- 哈希表:提供快速查找能力
- key到链表节点的映射
- 实现O(1)的查找速度
java复制class LRUCache {
// 双向链表节点定义
class DLinkedList {
int key, value;
DLinkedList prev, next;
public DLinkedList() {}
public DLinkedList(int key, int value) {
this.key = key;
this.value = value;
}
}
private Map<Integer, DLinkedList> cac
