我们有一个简单但非常常用的缓存,由 ConcurrentHashMap 实现。现在我们想要定期刷新所有值(例如,每 15 分钟)。
我想要这样的代码:
private void regularCacheCleanup() {
final long now = System.currentTimeMillis();
final long delta = now - cacheCleanupLastTime;
if (delta < 0 || delta > 15 * 60 * 1000) {
cacheCleanupLastTime = now;
clearCache();
}
}
除了它应该是:
- 线程安全
- 如果不清除缓存,则非阻塞且性能极佳
- 除了 java.* 类之外没有依赖项(因此没有 Google CacheBuilder)
- 坚如磐石 ;-)
- 无法开始新话题
现在我想在 ThreadLocal 中实现一个短定时器。当它到期时,将以同步方式检查真实计时器。然而,这是非常多的代码,所以更简单的想法会更好。
最佳答案
解决此问题的主流方法是使用一些计时器线程以指定的时间间隔刷新缓存。但是,由于您不需要创建新线程,我能想到的一种可能实现是伪定时缓存刷新。基本上,我会在缓存访问器(put 和 get 方法)中插入检查,每次客户端使用此方法时,我都会在执行 put 或 get 操作之前检查是否需要刷新缓存。这是粗略的想法:
class YourCache {
// holds the last time the cache has been refreshed in millis
private volatile long lastRefreshDate;
// indicates that cache is currently refreshing entries
private volatile boolean cacheCurrentlyRefreshing;
private Map cache = // Your concurrent map cache...
public void put(Object key, Object element) {
if (cacheNeedsRefresh()) {
refresh();
}
map.put(key, element);
}
public Object get(Object key) {
if (cacheNeedsRefresh()) {
refresh();
}
return map.get(key);
}
private boolean cacheNeedsRefresh() {
// make sure that cache is not currently being refreshed by some
// other thread.
if (cacheCurrentlyRefreshing) {
return false;
}
return (now - lastRefreshDate) >= REFRESH_INTERVAL;
}
private void refresh() {
// make sure the cache did not start refreshing between cacheNeedsRefresh()
// and refresh() by some other thread.
if (cacheCurrentlyRefreshing) {
return;
}
// signal to other threads that cache is currently being refreshed.
cacheCurrentlyRefreshing = true;
try {
// refresh your cache contents here
} finally {
// set the lastRefreshDate and signal that cache has finished
// refreshing to other threads.
lastRefreshDate = System.currentTimeMillis();
cahceCurrentlyRefreshing = false;
}
}
}
我个人不会考虑这样做,但如果您不想或不能创建计时器线程,那么这可能是您的一个选择。
请注意,虽然此实现避免了锁定,但由于竞争事件,它仍然容易出现重复刷新。如果这可以满足您的要求,那么应该没问题。但是,如果您有更严格的要求,那么您需要锁定以正确同步线程并避免竞争事件。
关于java - Java缓存超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12423502/