设计具有可变条目到期的Guava LoadingCache

fge*_*fge 27 java multithreading guava

我正在使用Guava的LoadingCache进入我的项目来处理线程(安全,友好)缓存加载,它运行得非常好.但是,存在限制.

定义缓存的当前代码如下所示:

cache = CacheBuilder.newBuilder().maximumSize(100L).build(new CacheLoader<K, V>()
{
    // load() method implemented here
}
Run Code Online (Sandbox Code Playgroud)

我没有指定到期时间.

问题是根据密钥的值,某些相关值可能会过期而其他值可能不会过期.并且CacheLoader不考虑这一点,如果您指定到期时间,则它适用于每个条目.

你会如何解决这个问题?

Jon*_*han 29

另一种选择是ExpiringMap,它支持变量输入到期:

Map<String, String> map = ExpiringMap.builder().variableExpiration().build();
map.put("foo", "bar", ExpirationPolicy.ACCESSED, 5, TimeUnit.MINUTES);
map.put("baz", "pez", ExpirationPolicy.CREATED, 10, TimeUnit.MINUTES);
Run Code Online (Sandbox Code Playgroud)


hoa*_*oaz 11

我建议您将过期时间直接包含在您的入门类中,如果从缓存中获取后立即过期,则从缓存中手动逐出它:

MyItem item = cache.getIfPresent(key);
if (item != null && item.isExpired()) {
    cache.invalidate(key);
    item = cache.get(key);
    // or use cache.put if you load it externally
}
Run Code Online (Sandbox Code Playgroud)

作为替代方案,我建议您检查支持每个元素到期策略的EhCache库.


Dim*_*eou 7

LoadingCache 提供了一些常用的过期策略,但是当这些策略不能满足您的需求时,您需要自己动手.

只需添加一个DelayQueue即可.每当您向缓存添加内容时Delayed,请使用适当的到期时间向该队列添加内容.该Delayed对象应该有一个(弱?)引用的关键.

最后一个要素是你需要定期轮询这个队列,看看是否有东西过期而且必须被驱逐.不一定要添加一个线程来执行此操作,您可以捎带访问任何线程LoadingCache.就在访问缓存之前,例如:

private void drainCache() {
  MyDelayed expired;
  while ((expired = delayedQueue.poll()) != null) {
    K key = expired.getReference();
    if (key != null) { // this only in case if you hold the key in a weak reference
      loadingCache.invalidate(key);
    }
  }
}

..
V lookup(K key) {
  drainCache();
  return loadingCache.getUnchecked(key);
}
Run Code Online (Sandbox Code Playgroud)