如何将条目填充到加载缓存番石榴中?

How to populate entries into Loading Cache guava?

我有一个用例,我想从多个线程将条目填充到数据结构中,并在达到特定大小后开始删除旧记录。所以我决定为此使用 Guava Loading Cache。

我想从多个线程将条目填充到我的加载缓存中,我将基于逐出的策略设置为 Size Based Eviction

  private final ScheduledExecutorService executorService = Executors
      .newSingleThreadScheduledExecutor();
  private final LoadingCache<String, DataBuilder> cache =
      CacheBuilder.newBuilder().maximumSize(10000000)
          .removalListener(RemovalListeners.asynchronous(new CustomListener(), executorService))
          .build(new CacheLoader<String, DataBuilder>() {
            @Override
            public DataBuilder load(String key) throws Exception {
              // what I should do here?
              // return 
            }
          });

// this will be called from multiple threads to populate the cache
public void addToCache(String key, DataBuilder dataBuilder) {
    // what I should do here?
    //cache.get(key).
}

我的 addToCache 方法将从多个线程调用以填充 cache。我很困惑我应该在 addToCache 方法中做什么来填充缓存以及我的 load 方法是什么样的?

这里 DataBuilder 是我的构建器模式。

显然你的问题是你没有得到 CacheLoader 的主要目的。

A CacheLoader 用于在调用 get(K key) or getUnchecked(K key) 时自动加载给定键(缓存中尚不存在)的值,即使我们有多个线程尝试要同时获取同一个键的值,实际上只有一个线程会加载该值,一旦完成,所有调用线程都将具有相同的值。

当加载值需要一些时间时,这通常很有用,例如当它是数据库访问或长时间计算的结果时,因为花费的时间越长,多个线程尝试的可能性就越高同时加载相同的值,如果没有一种机制确保只有一个线程将为所有调用线程加载数据,这将浪费资源。

所以这里假设您的 DataBuilder 的实例构建时间很长,或者您只需要确保所有线程对于给定的键都具有相同的实例,那么您确实需要一个 CacheLoader 它看起来像这样:

new CacheLoader<String, DataBuilder>() {
    @Override
    public DataBuilder load(String key) throws Exception {
        return callSomeMethodToBuildItFromTheKey(key); // could be new DataBuilder(key)
    }
}

感谢 CacheLoader,您无需再显式调用 put,因为您的缓存将由调用 cache.get(myKey) 或 [=22= 的线程在后台填充].

如果您想手动填充缓存,只需使用 put(K key, V value) method like any Cache 如下:

public void addToCache(String key, DataBuilder dataBuilder) {
    cache.put(key, dataBuilder);
}

如果您打算自己填充缓存,则不需要 CacheLoader,您只需调用 build() 而不是 build(CacheLoader<? super K1,V1> loader) 来构建您的 Cache实例(不再是 LoadingCache)。

您的代码将是:

private final Cache<String, DataBuilder> cache =
      CacheBuilder.newBuilder().maximumSize(10000000)
          .removalListener(
              RemovalListeners.asynchronous(new CustomListener(), executorService)
          ).build();