问题
I use ConcurrentLinkedHashMap as LRUCache
and I'm curious how it handles .get
after deletion
of a key (because we'll eventually have to remove keys from LRUCache
due to its policy.
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;
}
}
How can I handle these type of situations with this ConcurrentLinkedHashMap
class?
Thanks
回答1:
In this case, you would would want to avoid reading multiple times from the cache to avoid race conditions. Instead you would write this as,
Entity getEntity(GUID entityId) {
Entity entity = entityLRUCache.get(entityId);
if (entity == null) {
entity = longLoadFromDatabase(entityId);
entityLRUCache.put(entityId, entity);
}
return entity;
}
This has a race, called a cache stampede, when loading the value to populate on a miss. For that library, one might write a decorator using lock striping or storing futures to avoid this if problematic. The Google Code wiki used to provide an example of how to write a SelfPopulatingMap.
ConcurrentLinkedHashMap
merged into Guava and evolved into Caffeine. You should prefer that library, where you could write this as,
Entity getEntity(GUID entityId) {
return entityCache.get(entityId, this::longLoadFromDatabase);
}
来源:https://stackoverflow.com/questions/50078766/how-does-concurrentlinkedhashmap-builder-handles-deletions-and-get