Ich versuche, meinen eigenen LRU-Cache zu implementieren. Ja, ich weiß, dass Java zu diesem Zweck einen LinkedHashMap bereitstellt, aber ich versuche, es mit grundlegenden Datenstrukturen zu implementieren.ConcurrentModificationException beim Aktualisieren des gespeicherten Iterators (für die LRU-Cache-Implementierung)
Aus dem Lesen über dieses Thema, verstehe ich, dass ich eine HashMap für O (1) Lookup eines Schlüssels und eine verknüpfte Liste für die Verwaltung der "am wenigsten kürzlich verwendeten" Räumungsrichtlinie benötigt. Ich fand diese Referenzen, die alle eine Standardbibliothek hashmap verwenden, sondern ihre eigene verknüpfte Liste implementieren:
- "What data structures are commonly used for LRU caches and quickly locating objects?" (stackoverflow.com)
- "What is the best way to Implement a LRU Cache?" (quora.com)
- "Implement a LRU Cache in C++" (uml.edu)
- "LRU Cache (Java)" (programcreek.com)
der Hashtabelle soll, um direkt eine verknüpfte Liste Knoten speichern, wie I unten zeigen. Mein Cache sollte Integer-Schlüssel und String-Werte speichern.
jedoch in Java die LinkedList Sammlung deckt nicht seine inneren Knoten, also kann ich sie nicht in der HashMap speichern. Ich könnte stattdessen die HashMap speichern Indizes in die LinkedList, aber dann zu einem Artikel zu bekommen würde O (N) Zeit benötigen. Also habe ich versucht einen ListIterator zu speichern.
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.LinkedList;
import java.util.ListIterator;
public class LRUCache {
private static final int DEFAULT_MAX_CAPACITY = 10;
protected Map<Integer, ListIterator> _map = new HashMap<Integer, ListIterator>();
protected LinkedList<String> _list = new LinkedList<String>();
protected int _size = 0;
protected int _maxCapacity = 0;
public LRUCache(int maxCapacity) {
_maxCapacity = maxCapacity;
}
// Put the key, value pair into the LRU cache.
// The value is placed at the head of the linked list.
public void put(int key, String value) {
// Check to see if the key is already in the cache.
ListIterator iter = _map.get(key);
if (iter != null) {
// Key already exists, so remove it from the list.
iter.remove(); // Problem 1: ConcurrentModificationException!
}
// Add the new value to the front of the list.
_list.addFirst(value);
_map.put(key, _list.listIterator(0));
_size++;
// Check if we have exceeded the capacity.
if (_size > _maxCapacity) {
// Remove the least recently used item from the tail of the list.
_list.removeLast();
}
}
// Get the value associated with the key.
// Move value to the head of the linked list.
public String get(int key) {
String result = null;
ListIterator iter = _map.get(key);
if (iter != null) {
//result = iter
// Problem 2: HOW DO I GET THE STRING FROM THE ITERATOR?
}
return result;
}
public static void main(String argv[]) throws Exception {
LRUCache lruCache = new LRUCache(10);
lruCache.put(10, "This");
lruCache.put(20, "is");
lruCache.put(30, "a");
lruCache.put(40, "test");
lruCache.put(30, "some"); // Causes ConcurrentModificationException
}
}
So führt dies zu drei Problemen:
Problem 1: Ich erhalte eine ConcurrentModificationException, wenn ich den LinkedList aktualisiere den Iterator, die ich in der HashMap speichern.
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:953)
at java.util.LinkedList$ListItr.remove(LinkedList.java:919)
at LRUCache.put(LRUCache.java:31)
at LRUCache.main(LRUCache.java:71)
Problem 2. Wie kann ich den Wert abrufen, auf den der ListIterator zeigt? Es scheint, ich kann nur den nächsten() Wert abrufen.
Problem 3. Gibt es eine Möglichkeit, diesen LRU-Cache mithilfe der Java-Sammlungen LinkedList zu implementieren, oder muss ich wirklich meine eigene verknüpfte Liste implementieren?
Ja, es gibt keine Möglichkeit, dass Sie diese Arbeit machen. Sie müssen mindestens eine dieser Datenstrukturen manuell neu implementieren, wenn Sie dieses Rad neu erfinden wollen. –