缓存变暖是一个相当复杂的话题,因此有很多合理的方法,但不一定只有一个“正确”的方法。一个简单的选择是在未来交错的时间触发额外的写入,以重置到期时间:
public static <K, V> void staggerCacheExpiration(
Cache<K, V> cache, long maxExpiration, TimeUnit unit, ScheduledExecutorService scheduler) {
for (Entry<K, V> e : cache.asMap().entrySet()) {
long delay = ThreadLocalRandom.current().nextLong(0, maxExpiration);
scheduler.schedule(() -> cache.put(e.getKey(), e.getValue()), delay, unit);
}
}
任何依赖于Cache
自身的方法的一个关键问题是,只有在调用者需要该值时,才会最终触发(可能代价高昂的)刷新。最好不要使用expireAfterWrite()
或refreshAfterWrite()
运行一个专用线程来负责按顺序更新每个键。通过让单个线程更新所有键,您自然会避免同时刷新多个键的任何热点,并避免阻塞任何依赖缓存值的线程。
正如 Ben Manes 建议的那样,您可能更愿意将您的类型封装Cache
在您自己的类型中,这样您选择的任何行为都不会暴露给您的调用者。