Java 使用番石榴的理想缓存
在过去的几周里,我断断续续地试图用guava的方法找到理想的缓存实现。请看我前面的两个问题,并遵循我的思考过程 根据我所学到的,我的下一个尝试是放弃软值,转而支持maximumSize和expireAfterAccess:Java 使用番石榴的理想缓存,java,caching,guava,canonicalization,Java,Caching,Guava,Canonicalization,在过去的几周里,我断断续续地试图用guava的方法找到理想的缓存实现。请看我前面的两个问题,并遵循我的思考过程 根据我所学到的,我的下一个尝试是放弃软值,转而支持maximumSize和expireAfterAccess: ConcurrentMap<String, MyObject> cache = new MapMaker() .maximumSize(MAXIMUM_SIZE) .expireAfterAccess(MINUTES_TO_EXPI
ConcurrentMap<String, MyObject> cache = new MapMaker()
.maximumSize(MAXIMUM_SIZE)
.expireAfterAccess(MINUTES_TO_EXPIRY, TimeUnit.MINUTES)
.makeComputingMap(loadFunction);
ConcurrentMap cache=newmapmaker()
.最大尺寸(最大尺寸)
.expireAfterAccess(分钟到分钟到期,时间单位:分钟)
.makeComputingMap(加载函数);
在哪里
Function loadFunction=新函数(){
@凌驾
公共MyObject应用(字符串uidKey){
返回getFromDataBase(uidKey);
}
};
然而,我仍然要解决的一个问题是,一旦对象的时间到了,这个实现将逐出对象,即使它们是强可访问的。这可能会导致环境中有多个具有相同UID的对象浮动,这是我不想要的(我相信我试图实现的就是所谓的规范化)
因此,就我所知,唯一的答案是有一个额外的映射,它作为一个interner,我可以检查数据对象是否仍在内存中:
ConcurrentMap<String, MyObject> interner = new MapMaker()
.weakValues()
.makeMap();
ConcurrentMap interner=newmapmaker()
.weakValues()
.makeMap();
荷载函数将进行修改:
Function<String, MyObject> loadFunction = new Function<String, MyObject>() {
@Override
public MyObject apply(String uidKey) {
MyObject dataObject = interner.get(uidKey);
if (dataObject == null) {
dataObject = getFromDataBase(uidKey);
interner.put(uidKey, dataObject);
}
return dataObject;
}
};
Function loadFunction=新函数(){
@凌驾
公共MyObject应用(字符串uidKey){
MyObject数据对象=interner.get(uidKey);
if(dataObject==null){
dataObject=getFromDataBase(uidKey);
interner.put(uidKey,dataObject);
}
返回数据对象;
}
};
但是,在缓存中使用两个映射而不是一个映射似乎效率低下。有没有更复杂的方法来解决这个问题?一般来说,我这样做是正确的,还是应该重新考虑我的缓存策略?两个映射是否有效完全取决于getFromDatabase()的价格和对象的大小。这样做似乎并不超出所有合理的界限 至于实现,看起来您可能可以以稍微不同的方式分层映射,以获得所需的行为,并且仍然具有良好的并发属性
-dg我不明白这里的全部情况,但有两件事
Interners.newWeakInterner
+1谢谢,你说得对,loadFunction添加的逻辑正在做“interner”映射作为第二个计算映射所能做的事情。我认为这主要是一个装饰性的区别,因为“interner”映射只能通过即将到期的映射(已经在处理并发请求)访问,但更优雅。您的答案似乎支持我的做法-在接受输入之前,我要看看是否还有其他建议-我想我不完全理解使用weakKeys(),特别是如果键是String或UUID等。那么我是否需要一个包装器类作为键?此外,我还没有掌握使用弱键和抛弃基于时间和大小的驱逐的策略。我确实希望在访问后至少x分钟内保持缓存对象的强可访问性(或者我不希望?)。我的问题是,如果对象仍然碰巧处于长时间运行的进程中,那么之后会发生什么。可能是我遗漏了一些关于弱键的信息。关于“interner”-我考虑使用一个真正的interner,但是它只支持intern()方法,并且无法检查对象是否真的在其中。弱映射使我能够知道对象是否在内存中,或者是否需要加载。也许我用这个词太随便了?嘿,凯文,我接受达伦的回答,但如果你有机会的话,我希望你能澄清一下weakKeys()。谢谢虽然有点晚了,但您可能仍然有兴趣了解制作缓存的每个不同选项的内存成本:@DimitrisAndreou-非常有趣,感谢链接!一旦我开始更多地使用它们,我计划为
Cache
/CacheBuilder
更新这篇文章。
Function<String, MyObject> loadFunction = new Function<String, MyObject>() {
@Override
public MyObject apply(String uidKey) {
MyObject dataObject = interner.get(uidKey);
if (dataObject == null) {
dataObject = getFromDataBase(uidKey);
interner.put(uidKey, dataObject);
}
return dataObject;
}
};