Java Guava的Multimap和Cache组合

13

是否存在Guava的CacheMultimap功能的组合?本质上,我需要一个集合,在其中条目在给定时间后过期,例如在Cache中可用,但我有非唯一键,并且我需要条目独立地过期。

3个回答

5

我认为Louis Wasserman在上面的评论中已经给出了答案,即没有现成的MultimapCache组合可用。我通过下面的伪代码概述的解决方案解决了我的问题/需求:

private Cache<Integer,Object> cache = CacheBuilder.newBuilder().SomeConfig.build();
private Multimap<Integer,Object> multimap = HashMultimap<Integer, Object>.create();
private AtomicInteger atomicid = new AtomicInteger(0);

public void putInMultimap(int id, Object obj) {
   int mapid = atomicid.addAndGet(1);
   cache.put(mapid,obj);
   multimap.put(id,mapid);
}
public List<Object> getFromMultimap(int id) {
   Set<Integer> mapids = multimap.get(id);
   List<Object> list = new ArrayList<Object>();
   for (int i : mapids) {
      list.add(cache.getIfPresent(i));
   }
   return list;
}

这个简单的“解决方案”有一些限制,但对我来说还可以。


1
你如何处理不断增长的 multimap? - neu242
1
对于当前答案中的 SomeConfig 部分,您可以在那里添加一个 .removalListener 调用,每当从缓存中驱逐某些内容时都会调用它,以便您还可以将其从 multimap 中删除。 - Philipp Gayret

0

使用Guava Cache时没有put方法,缓存是设计为自动填充的。从键查找返回的值在运行时计算。Commons Collections Transformer Factories采用了类似的方法。

我认为你可以很容易地实现你要寻找的内容。如果你看一个简单的Map支持示例,比如Kitty-Cache,你会发现你可以用Multimap替换Map并相应地重写其他方法。所以在KittyCache.java内部,你可以有这样的东西:

Multimap<K, CacheEntry<V>> cache;

这种缓存的诀窍在于,直到有人请求它之前,什么都不会真正过期。

3
使用Guava Cache时并非没有put方法,该缓存被设计成可自行填充。事实上,Cache本身没有put方法,而LoadingCache则是被设计为自行填充的,但您仍然可以使用非加载缓存,并调用cache.asMap().put(...)来添加自己的条目。当然,这不能让您获得多重映射。只是更正了第一个陈述。 - Ray
2
自Guava 11.0版本以来,Cache中有一个[put方法](http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/cache/Cache.html#put(K, V))。您提供的示例很有趣,但我不能依赖于请求过期,我实现了RemovalListener来获取在Cache中过期时的通知。 - hgus1294
1
感谢您澄清这个问题,Ray。我引用的是:http://java.dzone.com/articles/google-guava-cache - Mark McLaren
当然,hgus1294是正确的——put是在11.0版本中添加的。我的错误。 - Ray
3
所有这些说法,Multimap 实现非常复杂,我们的内部实现不适用于处理缓存条目过期。这将是一个相当重要的项目。 =/ - Louis Wasserman
显示剩余4条评论

0
只要你谈论的是 Cache 而不是 LoadingCache,你就可以将 Cache.asMap() 视图传递到 Multimaps.newMultimap 中。

有趣。我进行了一些测试,但我无法使条目独立过期。根据您的建议,我将Cache.asMap()传递给了Multimaps.newMultimap,并使用expireAfterWrite设置为1000毫秒进行了一些快速测试,并运行了以下场景:map.put(1,Object1); Thread.Sleep(700) map.put(1,Object2); Thread.Sleep(500)。此时,我希望第一个条目被驱逐,但第二个条目仍然存在,但我发现两个条目都被驱逐了。也许我做错了什么,但除非我能改变这种行为,否则它对我没有用。 - hgus1294

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接