Caffeine和Ehcache的淘汰策略不可通过Comparator定制,因其采用W-TinyLFU或LRU等内置高效算法,不依赖排序;可通过权重、过期策略、分层缓存或EvictionAdvisor过滤间接影响淘汰。

Java 中的 Comparator 不能直接用于 Caffeine 或 Ehcache 的淘汰策略(如 LRU/LFU),因为这两种缓存库的淘汰机制是**内置且不可通过自定义 Comparator 替换的**。它们各自用高效、线程安全的内部数据结构(如 TinyLFU + W-TinyLFU)实现近似 LFU 或基于访问顺序的 LRU 行为,不暴露排序接口供用户传入 Comparator。
为什么不能用 Comparator 控制淘汰顺序?
Caffeine 和 Ehcache 的淘汰不是靠对 Entry 排序实现的,而是:
- Caffeine 使用 W-TinyLFU 算法:维护一个轻量级频率计数器 + LRU 队列,通过采样和准入策略决定驱逐,完全绕过全量排序;
-
Ehcache 3.x(基于 JSR-107)默认使用 LRU 或可配置 LFU,底层依赖
ConcurrentLinkedDeque和原子计数器,也不依赖 Comparator; - 缓存淘汰需高频、低延迟、无锁,而基于 Comparator 的排序(如
TreeSet或Collections.sort())时间复杂度高、难并发,不适合缓存场景。
如果想按特定字段“优先保留”,该怎么做?
虽然不能替换淘汰算法,但可通过以下方式间接影响缓存行为:
-
调整权重(Caffeine):用
weigher给不同 key/value 赋予不同权重,让“重要”条目占用更少权重,从而更难被淘汰; -
设置不同过期策略:对关键数据设更长
expireAfterWrite或启用refreshAfterWrite,变相延长驻留时间; - 分层缓存:把需“强保留”的数据放入独立缓存实例(如专用 small-size 高权重缓存),与普通数据隔离;
-
手动预热 + 锁定:对核心 key 调用
cache.get(key, loader)并定期 touch(如用cache.asMap().get(key)触发 access 计数),提升其在 LRU/LFU 中的优先级。
Ehcache 3 中的定制化限制
Ehcache 3 不支持用户替换淘汰策略。其 ResourcePools 和 EvictionAdvisor 仅能做“是否允许驱逐”的二元判断(返回 true 表示可淘汰),不能改变淘汰顺序或引入排序逻辑。例如:
立即学习“Java免费学习笔记(深入)”;
EvictionAdvisor<String, Object> advisor = (key, value) ->
!key.startsWith("critical."); // 只允许淘汰非 critical key
这只能过滤,不能让 “user:1001” 比 “user:1002” 更晚被淘汰——顺序仍由内置 LFU/LRU 决定。
替代思路:需要真正可控排序淘汰?考虑自己封装
若业务强依赖某种业务字段(如 lastAccessTime、score、热度值)排序淘汰,又无法接受 Caffeine/Ehcache 的近似策略,可:
- 用
ConcurrentHashMap + ConcurrentLinkedQueue自建 LRU 缓存,并在put时按自定义 Comparator 维护访问队列; - 用
LinkedHashMap(注意:非线程安全)重写removeEldestEntry,配合外部同步; - 引入 Redis + Sorted Set 做带分值的 LFU/LRU,用 ZINCRBY / ZREVRANGE 控制淘汰,再回源到本地缓存作二级加速。


















