Как 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);
}