如何基于时间戳条件删除Caffeine缓存中的指定条目?
基于时间戳批量删除Caffeine缓存的无遍历方案
有两种无需全量遍历缓存条目的实现方案,具体如下:
方案一:版本标记懒淘汰(性能最优)
核心思路是给每个缓存条目增加写入版本标记,全局维护最小生效版本,无需主动清理旧条目,读请求时自动判定是否失效。
实现步骤
- 定义缓存值包装类,额外存储写入时间戳/版本号:
// 也可以直接用写入时间戳作为版本号 record CacheWrapper<V>(long writeTimestamp, V value) {}
- 全局维护原子类型的最小生效时间戳:
// 初始值可设为0,代表所有时间写入的条目都生效 private final AtomicLong minValidWriteTime = new AtomicLong(0);
- 写入缓存时带上当前时间戳(建议使用
System.nanoTime(),和Caffeine内部时间逻辑一致,避免系统时间调整导致的异常):
cache.put(key, new CacheWrapper<>(System.nanoTime(), value));
- 读取缓存时做有效性校验,失效条目自动触发重新加载:
public V getCache(String key) { CacheWrapper<V> wrapper = cache.getIfPresent(key); // 条目不存在或者写入时间早于最小生效时间,都视为缓存失效 if (wrapper == null || wrapper.writeTimestamp() < minValidWriteTime.get()) { V newValue = loadFromDataSource(key); cache.put(key, new CacheWrapper<>(System.nanoTime(), newValue)); return newValue; } return wrapper.value(); }
- 需要淘汰所有T2之前的条目时,仅需修改全局最小生效时间:
// 无任何遍历操作,时间复杂度O(1) minValidWriteTime.set(T2);
适用场景
适合对性能要求极高,可接受少量未访问的旧条目暂时占用内存的场景,旧条目后续会被Caffeine自带的LRU/LFU驱逐策略自动清理。
方案二:时间分片缓存
核心思路是将缓存按时间窗口拆分为多个独立的Caffeine实例,淘汰指定时间之前的条目时直接销毁对应时间分片的缓存实例即可。
实现逻辑
- 按固定时间粒度(比如1分钟、5分钟)拆分缓存,每个时间窗口对应一个独立的Caffeine实例
- 写入时根据当前时间选择对应分片写入
- 读取时遍历所有未过期的分片查询数据
- 需要淘汰T2之前的所有条目时,直接销毁所有时间早于T2的分片实例即可,无需遍历条目
适用场景
适合需要精准控制内存占用,淘汰时间窗口固定的场景。
内容的提问来源于stack exchange,提问作者Boss Man
相关产品推荐
相关产品推荐

