我在做什么:我正在收集一个可能很大的对象集合,并要求用户根据集合进行输入。我想缓存对象以避免重新获取它们,但我希望收集在短时间后过期以防用户散失。如果需要,我会重新获取对象。该集合不会在短时间内发生变化。
我看过的内容:Guava's Cache因为基于时间的过期而看起来很有希望。然而,有几件事让我感到困扰。我真的不需要地图 - 集合将被完整访问或根本不访问。而且我担心我会遇到竞争条件,当我访问缓存时,缓存中的项目开始到期。这增加了一定程度的复杂性,必须跟踪我的所有项目是否都在缓存中,从而消除了缓存的一些价值。
我的问题:如果我不是将单个项目放入缓存中,而是将其中的单个项目放入缓存中并将其放入缓存中,我是否会遇到麻烦?这似乎是我一次访问整个集合的方式,并且集合在缓存中或者不在(在这种情况下我重建它)。我没有看到这种方法的缺陷吗?
答案 0 :(得分:5)
为Guava缓存提供静态单例密钥并不罕见。 Cache
即使不用作Map
,也会带来很多好处。我会做这样的事情:
private static final Object CACHE_KEY = new Object();
private LoadingCache<Object, List<SomeType>> cache =
CacheBuilder.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.softValues()
.build(valuesLoader());
//...
List<SomeType> values = cache.get(CACHE_KEY);
在我的代码库中,我在几个地方使用具有单个值的缓存,因此我将其抽象为SingleValueLoadingCache<T>
,它公开了一个无参数get()
方法并封装了缓存和关键。
这似乎是我一次访问整个集合的方式,并且集合在缓存中或者它不是(在这种情况下我重建它)。这种方法是否存在陷阱,我没有看到?
万一您尚未找到它,您可能希望LoadingCache
传递CacheLoader
build
CacheBuilder
方法。这样您就可以随时拨打get()
,如果该值不在缓存中,则会使用您提供的CacheLoader
自动同步加载。
答案 1 :(得分:1)
作为使用单个人工密钥的LoadingCache
的替代方法,您可以使用Suppliers.memoizeWithExpiration
,这会为您提供稍微简单的API。缺点是它没有公开Cache
所做的旋钮和统计数据。
private Supplier<Collection<Foo>> cachingSupplier =
Suppliers.memoizeWithExpiration(valueSupplier,
5L, TimeUnit.MINUTES);
答案 2 :(得分:0)
您的用例似乎将值描述为对象集合。因此,您描述的工作流程“制作一个Guava ImmutableCollection并将其放入缓存中”。是一个适当的行动。