ConcurrentHashMap vs ReentrantReadWriteLock basierte Custom Map für das Neuladen

8

Java Gurus,

Derzeit haben wir eine HashMap<String,SomeApplicationObject> , die häufig gelesen und gelegentlich geändert wird und wir haben Probleme, dass Lesen bei der Änderung / beim erneuten Laden null zurückgibt. was nicht akzeptabel ist.

Um das zu beheben, habe ich folgende Optionen:

A. Verwenden Sie ConcurrentHashMap

Was wie die erste Wahl aussieht, aber die Operation, von der wir sprechen, ist reload() - bedeutet clear() gefolgt von replaceAll() . Wenn also Map nach clear() und pre replaceAll() gelesen wird, gibt es null zurück, was nicht wünschenswert ist. Selbst wenn ich synchronize behebe, behebt dies das Problem nicht.

B. Erstellen Sie eine andere Implementierung basierend auf ReentrantReadWriteLock

Wo ich create Write Lock vor reload() operation erstellen würde. Dies scheint passender zu sein, aber ich denke, dass es dafür schon etwas geben muss und ich das Rad nicht neu erfinden muss.

Was ist der beste Ausweg?

BEARBEITEN Ist eine Sammlung bereits mit einer solchen Funktion verfügbar?

    
SiB 24.08.2012, 12:11
quelle

3 Antworten

4

Es scheint, dass Sie nicht sicher sind, wie das, was Peter Lawrey vorschlägt, umgesetzt werden kann. Es könnte so aussehen:

%Vor%

Es gibt keine Nebenläufigkeitsprobleme, weil:

  • Die neue Map wird über eine lokale Variable erstellt, die definitionsgemäß nicht geteilt wird - getNewValues muss nicht synchronisiert oder atomar sein
  • Die Zuordnung zu map ist atomar
  • map ist flüchtig, was garantiert, dass andere Threads die Änderung sehen
assylias 29.08.2012, 09:04
quelle
8

Da Sie die Map neu laden, würde ich sie bei einem Reload ersetzen.

Sie können dies tun, indem Sie eine flüchtige Map verwenden, die Sie bei der Aktualisierung vollständig ersetzen.

    
Peter Lawrey 24.08.2012 12:13
quelle
5

Dies klingt ein Los wie Guavas Cache , obwohl es wirklich darauf ankommt, wie Sie die Karte auffüllen und wie Sie die Werte berechnen. (Offenlegung: Ich trage zu Guava bei.)

Die eigentliche Frage ist, ob Sie angeben können, wie Sie Ihre SomeApplicationObject mit der Eingabe String berechnen. Nur basierend auf dem, was Sie uns bisher gesagt haben, könnte es in etwa so aussehen ...

%Vor%

Wenn Sie den Cache neu aufbauen möchten, rufen Sie einfach cache.invalidateAll() auf. Mit LoadingCache können Sie cache.get(key) aufrufen und wenn der Wert noch nicht berechnet wurde, wird er neu berechnet. Oder vielleicht nach dem Aufruf von cache.invalidateAll() , können Sie cache.loadAll(allKeys) aufrufen, obwohl Sie immer noch einzelne Elemente laden können, falls zwischen den invalidateAll und loadAll eine Anfrage eingeht.

Wenn das nicht akzeptabel ist - wenn Sie nicht einen Wert einzeln laden können, müssen Sie alle auf einmal laden - dann würde ich mit Peter Lawreys Ansatz fortfahren - behalten Sie eine volatile -Referenz bei eine Karte (im Idealfall ImmutableMap ), berechnen Sie die gesamte Karte neu und weisen Sie die neue Karte der Referenz zu, wenn Sie fertig sind.

    
Louis Wasserman 24.08.2012 16:21
quelle