Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何可靠地从Guava LoadingCache中删除记录?_Java_Multithreading_Caching_Guava_Google Guava Cache - Fatal编程技术网

Java 如何可靠地从Guava LoadingCache中删除记录?

Java 如何可靠地从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

我正在使用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

    }
  }
}
公共类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 to
increment
方法可能会非常慢,但我仍然希望每1分钟删除所有这些条目,并且我根本不在这个缓存上进行任何读取,只是写入它,然后通过发送到其他系统来删除这些记录。下面是我在番石榴中看到的

使用CacheBuilder生成的缓存不执行清除和逐出值 “自动”,或在值过期后立即,或 那种。相反,它在运行期间执行少量维护 写操作,或者在偶尔的读操作期间(如果写操作 稀罕的

那么
expireAfterWrite
是如何工作的呢?它是否像一个调度器一样工作,每1分钟运行一次,删除
clientdmetriccounterche
中的所有条目,然后在1分钟后再次唤醒,从同一个缓存中删除所有条目并继续这样做?读完维基后,我怀疑它是否能像那样工作。如果没有,那么我如何能够可靠地每1分钟删除一次这些记录并发送到其他系统,因为我的写入在一段时间内可能很少见


看起来我可能必须使用
Guava TimeLimiter
接口和
SimpleTimeLimiter
或者可能是
ScheduledExecutorService
来可靠地超时调用,然后删除条目?如果是,有人能提供一个例子,在我当前的例子中这是如何工作的吗?

对我来说,你似乎滥用了缓存,而映射就是这样。您使用的是无过期、无大小限制、无缓存,您只是在收集统计数据

您正在使用的唯一特性是加载方面,这并不值得

我建议使用
原子参考

  • 更新时,您可以通过
    AtomicReference::get
    获取当前分钟的版本
  • 使用
    clientId
    ,在
    ConcurrentHashMap
    中查找
    AtomicLongMap
    ,如果找不到,则创建一个新的(在Java 7上使用
    putIfAbsent
    ,在Java 8上使用
    ComputeFabSent
  • 使用
    名称
    ,您可以像您发布的那样更新
    AtomicLongMap
  • 每分钟通过
    AtomicReference::getAndSet
    替换一次所有内容
通过替换,您可以确保您的统计信息不会受到干扰,但是,您应该在
getAndSet
之后等待一段时间,因为可能有线程刚刚获取了引用并即将写入

它将产生比原来的方法更多的垃圾,但是所有垃圾的寿命都很短,因此您实际上可能会使GC更快乐

它很简单,不需要对库或其实现细节有深入的了解



我想,
volatile
而不是
AtomicReference
也可以。在我看来,你似乎误用了缓存,而映射也可以。您使用的是无过期、无大小限制、无缓存,您只是在收集统计数据

您正在使用的唯一特性是加载方面,这并不值得

我建议使用
原子参考

  • 更新时,您可以通过
    AtomicReference::get
    获取当前分钟的版本
  • 使用
    clientId
    ,在
    ConcurrentHashMap
    中查找
    AtomicLongMap
    ,如果找不到,则创建一个新的(在Java 7上使用
    putIfAbsent
    ,在Java 8上使用
    ComputeFabSent
  • 使用
    名称
    ,您可以像您发布的那样更新
    AtomicLongMap
  • 每分钟通过
    AtomicReference::getAndSet
    替换一次所有内容
通过替换,您可以确保您的统计信息不会受到干扰,但是,您应该在
getAndSet
之后等待一段时间,因为可能有线程刚刚获取了引用并即将写入

它会产生比原来的方法更多的垃圾,但是所有的垃圾都会很短,所以你