Redis淘汰策略共8种,包括noeviction、allkeys-lru、volatile-lru、allkeys-random、volatile-random、volatile-ttl、allkeys-lfu和volatile-lfu,分别基于不淘汰、LRU近似采样、随机删除、TTL优先及LFU频次衰减等机制适配不同业务场景。

Redis 的淘汰策略在 Java 中无法完全复现,因为 Redis 用的是近似 LRU(随机采样 + 时间戳),而 Java 常见实现是严格 LRU(哈希表 + 双向链表)。两者目标一致——淘汰“最近最少使用”的数据,但底层逻辑、性能开销和适用场景差异明显。
Java 严格 LRU:链表+哈希表的精确维护
这是最典型的工程实现,依赖双向链表记录访问顺序,哈希表保障 O(1) 查找:
- 每次 get 或 put 已存在 key 时,对应节点被移至链表头部(最新访问)
- 新 key 插入时也加到头部;容量超限时,直接删掉尾部节点(最久未访问)
- 哨兵头尾节点简化边界处理,避免空指针和分支判断
- 时间复杂度稳定为 O(1),空间开销略高(每个节点额外存 prev/next 引用)
Redis 近似 LRU:不维护全局顺序,靠采样和时间戳
Redis 不用双向链表,每个 key 的 redisObject 里只存一个 24 位 lru 字段(毫秒级时间戳,模 2²⁴):
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
- 淘汰时从所有 key 中随机抽取 N 个(默认 maxmemory-samples 5)
- 从中挑出 lru 值最小(即最后访问时间最早)的那个 key 删除
- 不保证绝对准确,但大幅降低内存与 CPU 开销,适合海量 key 场景
- 实际效果接近严格 LRU,尤其当 samples 增大时,但永远不是强一致性
变量置换逻辑的关键区别
所谓“变量置换”,本质是缓存项生命周期管理方式不同:
- Java 实现中,“变量”是 Node 对象,置换 = 物理移动节点位置 + 更新哈希引用
- Redis 中,“变量”是键值对,置换 = 比较时间戳 + 随机采样 + 单次删除
- Java 的置换触发明确(容量满即删尾),Redis 的置换是概率性、延迟性的,依赖配置和实时负载
- Java 能精确回答“谁是最久未用”,Redis 只能回答“大概率谁最久未用”
LFU 在 Java 和 Redis 中的对照参考
LFU 更强调访问频次而非时间,Java 模拟需额外维护频次计数器和按频次分组的链表结构:
- Java 可用两个 HashMap:一个映射 key→Node,一个映射 freq→FreqList(含多个节点)
- Redis 的 LFU 同样是近似实现:lru 字段复用为 16 位访问计数 + 8 位衰减时间戳,支持频次衰减防止历史热 key 长期霸榜
- 两者都比 LRU 多一层频次维度,但 Redis 的 LFU 同样不维护全量频次排序,靠采样和概率调整
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










