【发布时间】:2016-12-13 04:05:49
【问题描述】:
我正在使用 Guava LoadingCache 向其中填充一些数据,并且我想每 1 分钟从该 LoadingCache 中删除所有条目。
public class MetricHolder {
private final ExecutorService executor = Executors.newFixedThreadPool(2);
private final LoadingCache<String, AtomicLongMap<String>> clientIdMetricCounterCache =
CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES)
.removalListener(RemovalListeners.asynchronous(new SendToDatabase(), executor))
.build(new CacheLoader<String, AtomicLongMap<String>>() {
@Override
public AtomicLongMap<String> load(String key) throws Exception {
return AtomicLongMap.create();
}
});
private static class Holder {
private static final MetricHolder INSTANCE = new MetricHolder();
}
public static MetricHolder getInstance() {
return Holder.INSTANCE;
}
private MetricHolder() {}
public void increment(String clientId, String name) throws ExecutionException {
clientIdMetricCounterCache.get(clientId).incrementAndGet(name);
}
public LoadingCache<String, AtomicLongMap<String>> getClientIdMetricCounterCache() {
return clientIdMetricCounterCache;
}
private static class SendToDatabase implements RemovalListener<String, AtomicLongMap<String>> {
@Override
public void onRemoval(RemovalNotification<String, AtomicLongMap<String>> notification) {
String key = notification.getKey();
AtomicLongMap<String> value = notification.getValue();
System.out.println(key);
System.out.println(value);
// sending these key/value to some other system
}
}
}
我以多线程方式从代码中的许多不同位置调用increment 方法。因此,在 1 分钟内,它将在 clientIdMetricCounterCache 中填充大量指标。现在我想在每 1 分钟后可靠删除所有这些指标,并将所有这些指标发送到数据库。
在我的情况下,有时写入increment 方法可能非常慢,但我仍然想每 1 分钟删除所有这些条目,并且我根本没有在这个缓存上进行任何读取,只是写入它然后删除这些记录通过发送到其他系统。下面是我在番石榴看到的wiki
使用 CacheBuilder 构建的缓存不执行清理和逐出值 “自动”或值到期后立即,或任何 排序。相反,它在期间执行少量维护 写操作,或者在偶尔的读操作期间,如果写是 很少见。
那么expireAfterWrite 是如何工作的?它是否像调度程序一样工作,每 1 分钟运行一次并删除 clientIdMetricCounterCache 中的所有条目,然后它会在 1 分钟后再次唤醒并从同一个缓存中删除所有条目并继续这样?阅读 wiki 后,我怀疑它是否可以这样工作。如果没有,那么我如何可靠地每 1 分钟删除一次这些记录并发送到其他系统,因为我的写入可能在一段时间内很少见?
看起来我可能必须使用Guava TimeLimiter 接口和SimpleTimeLimiter 或者可能是ScheduledExecutorService 才能可靠地使呼叫超时然后丢弃条目?如果是,任何人都可以提供一个示例,这在我当前的示例中将如何工作?
【问题讨论】:
-
我看不出
TimeLimiter与任何事情有什么关系,但您引用的文档清楚地回答了这个问题:创建一个定期调用Cache.cleanUp()的后台线程。 -
值得注意的是,由于您是在 修改 缓存值而不是替换它们,如果另一个线程引用了
AtomicLongMap你正在尝试清理。 -
@shmosel 是的,我在 wiki 上看到了。我的困惑是我应该在后台线程中做什么?只需定期致电
Cache.cleanUp()意思是clientIdMetricCounterCache.cleanUp()?如果你能提供一个例子,那么这将消除我的困惑。 -
@shmosel 您在哪里看到我正在修改这些值而不是替换它们?
-
每次拨打
incrementAndGet()。
标签: java multithreading caching guava google-guava-cache