it-swarm.com.de

Einfacher, einfach zu verwendender LRU-Cache in java

Ich weiß, dass es einfach zu implementieren ist, aber ich möchte etwas wiederverwenden, das bereits vorhanden ist.

Das Problem, das ich lösen möchte, besteht darin, dass ich die Konfiguration (aus XML, damit ich sie zwischenspeichern kann) für verschiedene Seiten, Rollen usw. lade, sodass die Kombination der Eingaben sehr zunehmen kann (in 99% jedoch nicht). Um diese 1% zu bewältigen, möchte ich eine maximale Anzahl von Elementen im Cache haben ...

Bis ich weiß, dass ich org.Apache.commons.collections.map.LRUMap in Apache commons gefunden habe und es gut aussieht, aber auch etwas anderes überprüfen möchte. Irgendwelche Empfehlungen?

62
Juraj

Sie können ein LinkedHashMap (Java 1.4+) verwenden:

// 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);
98
Guido

Dies ist eine alte Frage, aber für die Nachwelt wollte ich ConcurrentLinkedHashMap auflisten, was im Gegensatz zu LRUMap threadsicher ist. Die Bedienung ist ganz einfach:

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

Und die Dokumentation hat einige gute Beispiele , wie man den LRU-Cache größenbasiert anstatt auf der Anzahl der Elemente basiert.

27
Bobby Powers

Hier ist meine Implementierung, mit der ich eine optimale Anzahl von Elementen im Speicher behalten kann.

Der Punkt ist, dass ich nicht nachverfolgen muss, welche Objekte aktuell verwendet werden, da ich eine Kombination aus LinkedHashMap für die MRU-Objekte und WeakHashMap für die LRU-Objekte verwende. Die Cache-Kapazität ist also nicht geringer als die MRU-Größe plus was auch immer der GC mir erlaubt. Immer wenn Objekte von der MRU fallen, werden sie an die LRU weitergeleitet, solange der GC über sie verfügt.

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

Ich hatte auch das gleiche Problem und ich habe keine guten Bibliotheken gefunden ... also habe ich meine eigenen erstellt.

simplelrucache bietet threadsicheres, sehr einfaches, nicht verteiltes LRU-Caching mit Unterstützung für TTL. Es bietet zwei Implementierungen

  • Concurrent basierend auf ConcurrentLinkedHashMap
  • Synchronisiert basierend auf LinkedHashMap

Sie finden es hier .

1
Daimon

Here ist ein sehr einfacher und einfach zu verwendender LRU-Cache in Java. Obwohl es kurz und einfach ist, ist es Produktionsqualität. Der Code wird erklärt (siehe README.md) und enthält einige Unit-Tests.

1
Barak