Java 如何可靠地从Guava LoadingCache中删除记录?
我正在使用GuavaJava 如何可靠地从Guava LoadingCache中删除记录?,java,multithreading,caching,guava,google-guava-cache,Java,Multithreading,Caching,Guava,Google Guava Cache,我正在使用GuavaLoadingCache向其中填充一些数据,我希望每1分钟从该LoadingCache中删除所有条目 public class MetricHolder { private final ExecutorService executor = Executors.newFixedThreadPool(2); private final LoadingCache<String, AtomicLongMap<String>> clientIdMetri
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
}
}
}
公共类MetricHolder{
private final executor服务executor=Executors.newFixedThreadPool(2);
专用最终加载缓存ClientIDMetricAccounterCache=
CacheBuilder.newBuilder().expireAfterWrite(1,TimeUnit.MINUTES)
.removalListener(RemovalListeners.asynchronous(新的SendToDatabase(),executor))
.build(新的缓存加载程序(){
@凌驾
公共AtomicLongMap加载(字符串键)引发异常{
返回AtomicLongMap.create();
}
});
私有静态类持有者{
私有静态最终MetricHolder实例=新MetricHolder();
}
公共静态MetricHolder getInstance(){
返回持有者实例;
}
专用MetricHolder(){}
public void increment(字符串clientId,字符串名称)引发ExecutionException{
clientdmetriccounterche.get(clientId.incrementAndGet(name);
}
公共加载缓存GetClientIDMetricAccounterCache(){
返回clientMetricAccounterCache;
}
私有静态类SendToDatabase实现RemovalListener{
@凌驾
移除时的公共无效(移除通知){
String key=notification.getKey();
AtomicLongMap value=notification.getValue();
系统输出打印项次(键);
系统输出打印项次(值);
//将这些密钥/值发送到其他系统
}
}
}
我正在以多线程方式从代码中的许多不同位置调用increment
方法。因此,在1分钟的时间内,它将填充clientdmetricAccounterche
中的许多度量。现在,我想在每1分钟后可靠地删除所有这些度量,并将所有这些度量发送到数据库
在我的例子中,有时write toincrement
方法可能会非常慢,但我仍然希望每1分钟删除所有这些条目,并且我根本不在这个缓存上进行任何读取,只是写入它,然后通过发送到其他系统来删除这些记录。下面是我在番石榴中看到的
使用CacheBuilder生成的缓存不执行清除和逐出值
“自动”,或在值过期后立即,或
那种。相反,它在运行期间执行少量维护
写操作,或者在偶尔的读操作期间(如果写操作
稀罕的
那么expireAfterWrite
是如何工作的呢?它是否像一个调度器一样工作,每1分钟运行一次,删除clientdmetriccounterche
中的所有条目,然后在1分钟后再次唤醒,从同一个缓存中删除所有条目并继续这样做?读完维基后,我怀疑它是否能像那样工作。如果没有,那么我如何能够可靠地每1分钟删除一次这些记录并发送到其他系统,因为我的写入在一段时间内可能很少见
看起来我可能必须使用
Guava TimeLimiter
接口和SimpleTimeLimiter
或者可能是ScheduledExecutorService
来可靠地超时调用,然后删除条目?如果是,有人能提供一个例子,在我当前的例子中这是如何工作的吗?对我来说,你似乎滥用了缓存,而映射就是这样。您使用的是无过期、无大小限制、无缓存,您只是在收集统计数据
您正在使用的唯一特性是加载方面,这并不值得
我建议使用原子参考
:
- 更新时,您可以通过
获取当前分钟的版本AtomicReference::get
- 使用
,在clientId
中查找ConcurrentHashMap
,如果找不到,则创建一个新的(在Java 7上使用AtomicLongMap
,在Java 8上使用putIfAbsent
)ComputeFabSent
- 使用
,您可以像您发布的那样更新名称
AtomicLongMap
- 每分钟通过
替换一次所有内容AtomicReference::getAndSet
getAndSet
之后等待一段时间,因为可能有线程刚刚获取了引用并即将写入
它将产生比原来的方法更多的垃圾,但是所有垃圾的寿命都很短,因此您实际上可能会使GC更快乐
它很简单,不需要对库或其实现细节有深入的了解
我想,
volatile
而不是AtomicReference
也可以。在我看来,你似乎误用了缓存,而映射也可以。您使用的是无过期、无大小限制、无缓存,您只是在收集统计数据
您正在使用的唯一特性是加载方面,这并不值得
我建议使用原子参考
:
- 更新时,您可以通过
获取当前分钟的版本AtomicReference::get
- 使用
,在clientId
中查找ConcurrentHashMap
,如果找不到,则创建一个新的(在Java 7上使用AtomicLongMap
,在Java 8上使用putIfAbsent
)ComputeFabSent
- 使用
,您可以像您发布的那样更新名称
AtomicLongMap
- 每分钟通过
替换一次所有内容AtomicReference::getAndSet
getAndSet
之后等待一段时间,因为可能有线程刚刚获取了引用并即将写入
它会产生比原来的方法更多的垃圾,但是所有的垃圾都会很短,所以你