Время от времени в течение последних нескольких недель я пытался найти свою идеальную реализацию кеша, используя MapMaker. См. мои предыдущие два вопроса здесь и здесь, чтобы следовать моему мыслительному процессу.
Принимая во внимание то, что я узнал, моей следующей попыткой будет отказаться от мягких значений в пользу maxSize и 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;
}
};
Однако использование двух карт вместо одной для кеша кажется неэффективным. Есть ли более сложный способ приблизиться к этому? В общем, правильно ли я это делаю, или мне следует переосмыслить свою стратегию кэширования?
Cache
/CacheBuilder
, как только поиграю с ними побольше. - person Paul Bellora   schedule 09.02.2012