Как ConcurrentLinkedHashMap.Builder обрабатывает удаление и получает? - PullRequest
0 голосов
/ 28 апреля 2018

Я использую ConcurrentLinkedHashMap как LRUCache, и мне интересно, как он обрабатывает .get после deletion ключа (потому что в конечном итоге нам придется удалить ключи из LRUCache из-за его политика.

entityLRUCache = new ConcurrentLinkedHashMap.Builder<GUID, Entity>()
                                            .maximumWeightedCapacity(100)
                                            .build();

...

Entity getEntity(GUID entityId)
{
    if (entityLRUCache.containsKey(entityId))
    {
        // Question: what if key gets deleted from other 
        // thread (when we jumped into this if statement) 
        // and then we'll try to retrieve it here using .get()
        return entityLRUCache.get(entityId);
    }
    else
    {
        Entity entity = longLoadFromDatabase(entityId);
        entityLRUCache.put(entityId, entity);
        return entity;
    }
}

Как я могу справиться с такими ситуациями с помощью этого ConcurrentLinkedHashMap класса?

Спасибо

1 Ответ

0 голосов
/ 28 апреля 2018

В этом случае вам следует избегать многократного чтения из кэша, чтобы избежать условий гонки. Вместо этого вы бы написали это как

Entity getEntity(GUID entityId) {
  Entity entity = entityLRUCache.get(entityId);
  if (entity == null) {
    entity = longLoadFromDatabase(entityId);
    entityLRUCache.put(entityId, entity);
  }
  return entity;
}

Это гонка, называемая кэш-давкой, при загрузке значения для заполнения при промахе. Для этой библиотеки можно написать декоратор, используя чередование блокировок или сохраняя фьючерсы, чтобы избежать этого, если возникнут проблемы. Вики-код Google, используемый в качестве примера того, как написать SelfPopulationMap .

ConcurrentLinkedHashMap слился с гуавой и превратился в кофеин . Вы должны предпочесть ту библиотеку, где вы могли бы написать это как

Entity getEntity(GUID entityId) {
  return entityCache.get(entityId, this::longLoadFromDatabase);
}
...