Erstellen und setzen Sie einen Map-Wert nur, wenn dieser nicht bereits vorhanden ist, und holen Sie sich eine thread-sichere Implementierung

8

Was ist der beste Weg, um diesen Code threadsicher zu machen?

%Vor%

Hier sind die paar Lösungen, an die ich denken könnte:

  1. Ich könnte ein ConcurrentHashMap verwenden, aber wenn ich es gut verstanden habe, macht es nur die atomaren put und get Operationen threadsicher, dh es stellt nicht sicher, dass buildB() Methode, die nur einmal für einen bestimmten Wert aufgerufen wird.
  2. Ich könnte Collections.synchronizedMap(new HashMap<A, B>()) verwenden, aber ich hätte das gleiche Problem wie der erste Punkt.
  3. Ich könnte die ganze putIfNeededAndGet() Methode synchronized setzen, aber ich kann wirklich viele Threads haben, die auf diese Methode zugreifen, also könnte es ziemlich teuer sein.
  4. Ich könnte das doppelt überprüfte Sperrmuster verwenden, aber es gibt immer noch das zugehörige Problem Out-of-Order-Schreibprobleme .

Welche anderen Lösungen könnte ich haben?

Ich weiß, dass dies ein ziemlich häufiges Thema im Web ist, aber ich habe noch kein klares, vollständiges und funktionierendes Beispiel gefunden.

    
sp00m 13.11.2013, 09:14
quelle

4 Antworten

2

Dies ist möglicherweise nicht die Antwort, die Sie suchen, aber verwenden Sie die Guava CacheBuilder , das macht schon alles und noch mehr:

%Vor%

Sie können auch einfach das zeitgesteuerte Ablaufdatum und andere Funktionen hinzufügen.

Dieser Cache stellt sicher, dass load() (oder in Ihrem Fall buildB ) nicht gleichzeitig mit demselben key aufgerufen wird. Wenn ein Thread bereits ein B erstellt, wartet jeder andere Aufrufer nur auf diesen Thread.

    
Joachim Sauer 13.11.2013, 09:36
quelle
5

Verwenden Sie ConcurrentHashMap und das Lazy-Init-Muster, das Sie verwendet haben

%Vor%     
Evgeniy Dorofeev 13.11.2013 09:30
quelle
2

In der obigen Lösung ist es möglich, dass viele Threads die Klasse processB(...) gleichzeitig haben und alle berechnen. Aber in meinem Fall benutze ich Future und einen einzelnen Thread bekomme nur den alten Wert als null daher wird nur der processB Rest berechnet wird auf f.get() warten.

%Vor%     
Trying 13.11.2013 09:46
quelle
1

Dachte vielleicht, dass dies auch für jemand anderen nützlich sein wird. Mit Java 8 lambdas habe ich diese Funktion erstellt, die für mich großartig funktioniert hat:

%Vor%

Dann kannst du es so benutzen:

%Vor%

Ich habe dies für etwas Bestimmtes erstellt, aber den Kontext und den Code zu einem allgemeineren Aussehen geändert, deshalb hat meine creationFunction einen Parameter, er kann auch keine Parameter haben ...

auch Sie können es mehr generieren, indem Sie Object in einen generischen Typ ändern, wenn es nicht klar ist, lassen Sie es mich wissen und ich werde ein weiteres Beispiel hinzufügen.

UPDATE:

Ich habe gerade von Map.computeIfAbsent erfahren, was im Grunde dasselbe ist, ich liebe java 8 :)

    
keisar 22.03.2016 18:58
quelle

Tags und Links