Sto tentando di implementare la mia cache LRU. Sì, so che Java fornisce uno LinkedHashMap per questo scopo, ma sto cercando di implementarlo utilizzando le strutture di dati di base.ConcurrentModificationException durante l'aggiornamento di Iterator memorizzato (per l'implementazione della cache LRU)
Dalla lettura di questo argomento, comprendo che ho bisogno di una HashMap per O (1) ricerca di una chiave e di un elenco collegato per la gestione della politica di sfratto "meno recente". Ho trovato questi riferimenti che utilizzano tutti un hashmap libreria standard, ma attuare le proprie lista collegata:
- "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)
La tabella hash dovrebbe memorizzare direttamente un elenco nodo legato come mostro qui di seguito. La mia cache dovrebbe memorizzare chiavi Integer e valori String.
Tuttavia, in Java collezione LinkedList non espone i suoi nodi interni, quindi non li può memorizzare all'interno del HashMap. Potrei invece avere gli indici del negozio HashMap in LinkedList, ma poi arrivare a un elemento richiederebbe O (N) tempo. Così ho provato a memorizzare un ListIterator.
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
}
}
Quindi questo porta a tre problemi:
Problema 1: sto ottenendo un ConcurrentModificationException quando aggiorno il LinkedList utilizzando l'iteratore che posso conservare nel HashMap.
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)
Problema 2. Come posso recuperare il valore indicato da ListIterator? Sembra che io possa solo recuperare il valore next().
Problema 3. Esiste un modo per implementare questa cache LRU utilizzando la raccolta LinkedList Java o devo implementare la mia lista concatenata?
Sì, non c'è modo che tu possa fare quel lavoro. Dovrai reimplementare manualmente almeno una di queste strutture dati se vuoi reinventare questa ruota. –