Frage

Ich habe LinkedHashMap mit accessOrder wahr zusammen mit ermöglicht maximal 500 Einträge jederzeit als LRU-Cache für Daten verwendet. Aber aufgrund der Skalierbarkeit Probleme möchte ich einige Thread-sichere Alternative zu bewegen. ConcurrentHashMap scheint gut in dieser Hinsicht, aber es fehlt die Eigenschaften accessOrder und removeEldestEntry(Map.Entry e) in LinkedHashMap gefunden. Kann jemand zu einem gewissen Punkt Link oder mir helfen, die Umsetzung zu erleichtern.

War es hilfreich?

Lösung

Ich tat etwas ähnliches vor kurzem mit ConcurrentHashMap<String,CacheEntry>, wo Cacheentry dem Artikel wickelt und fügt Cache Räumungsstatistiken: Ablaufzeit, Einführungszeit (für FIFO / LIFO Räumung), zuletzt verwendete Zeit (LRU / MRU Räumung), die Anzahl der Treffer (für LFU / MFU Räumungs) usw. die eigentlichen Räumungs synchronisiert und erzeugen eine ArrayList<CacheEntry> und machen einen Collections.sort () auf den entsprechenden Komparator für die Räumungsstrategie verwendet wird. Da dies teuer ist, lops jede Räumungs dann den Boden 5% der CacheEntries ab. Ich bin sicher, Performance-Tuning obwohl helfen würde.

In Ihrem Fall, da Sie FIFO tun, könnten Sie eine separate halten ConcurrentLinkedQueue . Wenn Sie ein Objekt in den ConcurrentHashMap hinzuzufügen, führen Sie einen ConcurrentLinkedQueue.add () dieses Objekts. Wenn Sie einen Eintrag vertreiben wollen, tun ein ConcurrentLinkedQueue.poll (), um das älteste Objekt zu entfernen, ist es dann auch aus dem ConcurrentHashMap entfernen.

Update: Weitere Möglichkeiten in diesem Bereich sind ein Java Collections Synchronisation Wrapper und die Java 1.6 ConcurrentSkipListMap .

Andere Tipps

Haben Sie versucht, eine der vielen Caching-Lösungen wie ehcache verwenden? Sie könnten versuchen, mit einem ReadWriteLock mit LinkedHashMap. Dies würde die gleichzeitigen Lesezugriff geben.

Dies könnte alt scheint jetzt, aber zumindest nur für meine eigene Geschichte Tracking, ich werde meine Lösung hier hinzufügen: Ich ConcurrentHashMap kombiniert, die K- Karten> Unterklasse von WeakReference, ConcurrentLinkedQueue und einer Schnittstelle, die Deserialisierung definiert die Wertobjekte basierend auf K LRU Caching korrekt funktionieren. Die Warteschlange enthält starke refs, und der GC werden die Werte aus dem Speicher, wenn entsprechende evict. die Größe der Warteschlange beteiligt Atomicinteger Tracking, da Sie nicht wirklich die Warteschlange überprüfen können, um zu bestimmen, wenn gewaltsam zu vertreiben. Der Cache wird Räumung Griff aus / in die Warteschlange hinzufügen, sowie Kartenmanagement. Wenn der GC den Wert aus dem Speicher geräumt wird behandeln die Umsetzung der Deserialisierung Schnittstelle zurück, um den Wert abzurufen. Ich hatte auch eine andere Implementierung, die auf der Festplatte / Re-Lektüre beteiligt Spooling was gespult wurde, aber das war viel langsamer als die Lösung, die ich hier gepostet, wie Ihad Spooling / Lesen zu synchronisieren.

Sie erwähnen wollen Skalierbarkeit Probleme mit einer „Thread-sicheren“ Alternative zu lösen. „Thread-Sicherheit“ bedeutet hier, dass die Struktur tolerant von Versuchen, bei gleichzeitigem Zugriff, da sie nicht der Korruption durch die gleichzeitige Nutzung ohne externe Synchronisation leiden. Allerdings ist eine solche Toleranz nicht unbedingt helfen „Skalierbarkeit“ zu verbessern. Im einfachsten - wenn auch meist fehlgeleitet - Ansatz, werden Sie versuchen, Ihre Struktur intern zu synchronisieren und noch verlassen Nicht-Atom Check-dann-act Operationen unsicher

.

LRU-Caches erfordert zumindest ein gewisses Bewusstsein der gesamten Struktur. Sie brauchen so etwas wie eine Zählung der Mitglieder oder die Größe der Mitglieder zu entscheiden, wann gewaltsam zu vertreiben, und dann müssen sie die Räumung mit gleichzeitigen Versuchen koordinieren zu können, lesen, hinzufügen oder Elemente entfernen. Der Versuch, die Synchronisation, die für die gleichzeitigen Zugriff auf die „main“ Struktur kämpft gegen den Räumungsmechanismus zu reduzieren, und zwingt die Räumungspolitik weniger präzise in seinen Garantien.

Die derzeit akzeptierte Antwort erwähnt „wenn Sie einen Eintrag vertreiben wollen“. Darin liegt das Problem. Wie wissen Sie, wenn Sie einen Eintrag vertreiben wollen? Welche anderen Operationen tun Sie, um pausieren müssen diese Entscheidung zu treffen?

Wickeln Sie die Karte in einem Collections.synchronizedMap(). Wenn Sie weitere Methoden aufrufen müssen, dann auf der Karte synchronize, die Sie zurück von diesem Anruf bekam, und die ursprüngliche Methode auf dem ursprünglichen Karte aufrufen ( sehen die javadocs für ein Beispiel ). Das gleiche gilt, wenn Sie über die Tasten laufen, etc.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top