мой идеальный кеш с использованием guava

Время от времени последние несколько недель я пытался найти свою идеальную реализацию кеширования, используя MapMaker от guava. См. Мои предыдущие два вопроса здесь и здесь , чтобы следить за моим мыслительным процессом.

Принимая то, что я узнал, моя следующая попытка собирается отказаться от мягких значений в пользу максимального размера и expireAfterAccess:

ConcurrentMap cache = new MapMaker()
        .maximumSize(MAXIMUM_SIZE)
        .expireAfterAccess(MINUTES_TO_EXPIRY, TimeUnit.MINUTES)
        .makeComputingMap(loadFunction);

where

Function loadFunction = new Function() {
   @Override
   public MyObject apply(String uidKey) {
      return getFromDataBase(uidKey);
   }
};

Однако одна остающаяся проблема, с которой я все еще борюсь, заключается в том, что эта реализация будет вытеснять объекты, даже если они сильно достижимы, когда их время истекло. Это может привести к тому, что в среде будут перемещаться несколько объектов с одинаковым UID, чего я не хочу (я считаю, что то, что я пытаюсь достичь, известно как канонизация).

Итак, насколько я могу судить, единственный ответ - иметь дополнительную карту, которая функционирует как интернер, которую я могу проверить, чтобы увидеть, находится ли объект данных все еще в памяти:

ConcurrentMap interner = new MapMaker()
        .weakValues()
        .makeMap();

, и функция загрузки будет пересмотрена:

Function loadFunction = new Function() {
   @Override
   public MyObject apply(String uidKey) {
      MyObject dataObject = interner.get(uidKey);
      if (dataObject == null) {
         dataObject = getFromDataBase(uidKey);
         interner.put(uidKey, dataObject);
      }
      return dataObject;
   }
};

Однако использование двух карт вместо одной для кеш кажется неэффективным. Есть ли более изощренный подход к этому? В общем, правильно ли я поступаю, или мне следует переосмыслить свою стратегию кэширования?

20
задан Community 23 May 2017 в 11:45
поделиться