Pregunta

Sé que es fácil de implementar, pero quiero reutilizar algo que ya existe.

El problema que quiero resolver es que cargue la configuración (desde XML, así que quiero guardarlos en caché) para diferentes páginas, roles, ... así que la combinación de entradas puede crecer bastante (pero en el 99% no). Para manejar este 1%, quiero tener un número máximo de elementos en caché ...

Hasta que sepa que he encontrado org.apache.commons.collections.map.LRUMap en apache commons y se ve bien, pero también quiero verificar otra cosa. ¿Alguna recomendación?

¿Fue útil?

Solución

Puede usar un 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);

Otros consejos

Esta es una pregunta antigua, pero para la posteridad quería listar ConcurrentLinkedHashMap , que es hilo seguro, a diferencia de LRUMap . El uso es bastante fácil:

ConcurrentMap<K, V> cache = new ConcurrentLinkedHashMap.Builder<K, V>()
    .maximumWeightedCapacity(1000)
    .build();

Y la documentación tiene algunos buenos ejemplos , como cómo hacer LRU caché basado en el tamaño en lugar de la cantidad de elementos basados.

Aquí está mi implementación que me permite mantener un número óptimo de elementos en la memoria.

El punto es que no necesito hacer un seguimiento de los objetos que se están utilizando actualmente, ya que estoy usando una combinación de LinkedHashMap para los objetos MRU y WeakHashMap para los objetos LRU. Por lo tanto, la capacidad del caché no es menor que el tamaño de MRU más lo que el GC me permita mantener. Cada vez que los objetos se caen del MRU, van al LRU durante el tiempo que el GC los tenga.

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);
}
}

También tuve el mismo problema y no he encontrado ninguna buena biblioteca ... así que he creado la mía.

simplelrucache proporciona almacenamiento en caché LRU, muy simple, no distribuido y seguro para subprocesos con soporte TTL. Proporciona dos implementaciones

  • Concurrente basado en ConcurrentLinkedHashMap
  • sincronizado basado en LinkedHashMap

Puede encontrarlo aquí .

Aquí es un caché LRU muy simple y fácil de usar en Java. Aunque es corto y simple es calidad de producción. El código se explica (consulte el archivo README.md) y tiene algunas pruebas unitarias.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top