Как ConcurrentLinkedHashMap.Builder обрабатывает удаление и получает?

Я использую 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 ответ

Решение

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

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);
}
Другие вопросы по тегам