Fácil, simples de usar o cache LRU em Java
Pergunta
Eu sei que é simples de implementar, mas eu quero a reutilização algo que já existe.
Problema Quero resolver é que a configuração I carga (de XML assim que eu quero cache-los) para diferentes páginas, papéis, ... então a combinação de entradas pode crescer bastante grande (mas em 99% não). Para lidar com esse 1%, eu quero ter um número máximo de itens no cache ...
Até sei que tenho encontrado org.apache.commons.collections.map.LRUMap no Apache Commons e ele parece estar bom, mas quero verificar também outra coisa. Quaisquer recomendações?
Solução
Você pode usar um LinkedHashMap (Java 1.4+):
// Create cache
final int MAX_ENTRIES = 100;
Map cache = new LinkedHashMap(MAX_ENTRIES+1, .75F, true) {
// This method is called just after a new entry has been added
public boolean removeEldestEntry(Map.Entry eldest) {
return size() > MAX_ENTRIES;
}
};
// Add to cache
Object key = "key";
cache.put(key, object);
// Get object
Object o = cache.get(key);
if (o == null && !cache.containsKey(key)) {
// Object not in cache. If null is not a possible value in the cache,
// the call to cache.contains(key) is not needed
}
// If the cache is to be used by multiple threads,
// the cache must be wrapped with code to synchronize the methods
cache = (Map)Collections.synchronizedMap(cache);
Outras dicas
Esta é uma questão de idade, mas para a posteridade eu queria listar ConcurrentLinkedHashMap , que é o segmento de seguros, ao contrário LRUMap . O uso é bastante fácil:
ConcurrentMap<K, V> cache = new ConcurrentLinkedHashMap.Builder<K, V>()
.maximumWeightedCapacity(1000)
.build();
E a documentação tem algumas boas exemplos , como forma de tornar o LRU cache de tamanho baseada em vez de número-of-itens com base.
Aqui está minha implementação que me permite manter um número ideal de elementos de memória.
A questão é que eu não preciso acompanhar o que os objetos estão sendo usados ??desde que eu estou usando uma combinação de um LinkedHashMap para o MRU objetos e uma WeakHashMap para os objetos LRU. Assim, a capacidade de cache não é menos do que o tamanho MRU mais o que o GC me permite manter. Sempre que os objetos caem fora do MRU eles vão para o LRU enquanto o GC vai tê-los.
public class Cache<K,V> {
final Map<K,V> MRUdata;
final Map<K,V> LRUdata;
public Cache(final int capacity)
{
LRUdata = new WeakHashMap<K, V>();
MRUdata = new LinkedHashMap<K, V>(capacity+1, 1.0f, true) {
protected boolean removeEldestEntry(Map.Entry<K,V> entry)
{
if (this.size() > capacity) {
LRUdata.put(entry.getKey(), entry.getValue());
return true;
}
return false;
};
};
}
public synchronized V tryGet(K key)
{
V value = MRUdata.get(key);
if (value!=null)
return value;
value = LRUdata.get(key);
if (value!=null) {
LRUdata.remove(key);
MRUdata.put(key, value);
}
return value;
}
public synchronized void set(K key, V value)
{
LRUdata.remove(key);
MRUdata.put(key, value);
}
}
Eu também tive mesmo problema e eu não encontrei qualquer boas bibliotecas ... assim que eu criei minha própria.
simplelrucache fornece threadsafe, muito simples cache LRU, não distribuído com apoio TTL. Ele fornece duas implementações
- Concurrent baseado em ConcurrentLinkedHashMap
- sincronizado baseado em LinkedHashMap
Você pode encontrá-lo aqui .
Aqui é muito simples e fácil de usar o cache LRU em Java. Embora seja curta e simples é a qualidade da produção. O código é explicada (olhar para o README.md) e tem alguns testes de unidade.