在过去的几周里,我断断续续地尝试使用番石榴的MapMaker找到我理想的缓存实现。请在此处和此处查看我之前的两个问题,以了解我的思考过程。
根据我所学到的,我的下一次尝试是放弃软值,转而使用 maximumSize 和 expireAfterAccess:
ConcurrentMap<String, MyObject> cache = new MapMaker()
.maximumSize(MAXIMUM_SIZE)
.expireAfterAccess(MINUTES_TO_EXPIRY, TimeUnit.MINUTES)
.makeComputingMap(loadFunction);
在哪里
Function<String, MyObject> loadFunction = new Function<String, MyObject>() {
@Override
public MyObject apply(String uidKey) {
return getFromDataBase(uidKey);
}
};
但是,我仍然在努力解决的一个剩余问题是,一旦对象的时间到了,即使对象是可强烈访问的,此实现也会驱逐对象。这可能会导致具有相同 UID 的多个对象在环境中浮动,这是我不希望的(我相信我想要实现的目标被称为规范化)。
所以据我所知,唯一的答案是有一个额外的地图,它作为一个内部人,我可以检查一个数据对象是否仍在内存中:
ConcurrentMap<String, MyObject> interner = new MapMaker()
.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;
}
};
但是,使用两个映射而不是一个映射来缓存似乎效率低下。有没有更复杂的方法来解决这个问题?一般来说,我是否以正确的方式进行此操作,还是应该重新考虑我的缓存策略?