2016-11-15 5 views
3

Gibt es eine Möglichkeit, einen Code nur auszuführen, wenn der Schlüssel nicht in einer ConcurrentHashMap existiert, und das Ergebnis des Codes in der Sammlung zu speichern?Äquivalent von ComputeIfAbsent in Java 7

Ich kann Java 8 Funktionen nicht verwenden, weil ich für Android entwickle.

Auch würde ich gerne lange Operationen vermeiden, wenn ich nicht muss, und ich will nicht die atomare Operation der Sammlung zu brechen, um dies zu tun.

+2

Gibt es etwas über 'if (! Map.containsKey (key))', das nicht für Sie funktioniert? – Zircon

+1

@Zircon computeIfAbsent fügt das Ergebnis der Funktion atomisch als neuen Wert für diesen Schlüssel ein. Das ist also kein 100% Ersatz ohne zusätzliche Arbeit. –

+0

@SotiriosDelimanolis Er sagt ausdrücklich, er will, dass es atomar ist. Also nein, es gibt kein Äquivalent. Sie können ein Äquivalent schreiben, aber Sie müssen Ihre eigenen Sperren mit einem expliziten Semaphor durchführen. –

Antwort

-1

Nein. Der Weg, um es zum Laufen zu bringen, besteht darin, ein eigenes Schloss oben auf der Karte zu verwenden.

4

Es gibt keine genaue Entsprechung, aber die übliche Vorgehensweise ist so etwas wie diese:

ConcurrentMap<Key,Value> map = ... 

Value computeIfAbsent(Key k) { 
    Value v = map.get(k); 
    if (v == null) { 
    Value vNew = new Value(...); // or whatever else you do to compute the value 
    v = (v = map.putIfAbsent(k, vNew)) == null ? vNew : v; 
    } 
    return v; 
} 

Das ist so ziemlich funktional äquivalent der computeIfAbsent Anruf in Java 8, mit dem einzigen Unterschied, dass manchmal konstruieren Sie ein Value Objekt, das es niemals in die Map schafft - weil ein anderer Thread es zuerst eingefügt hat. Es führt nie dazu, das falsche Objekt oder etwas Ähnliches zurückzugeben - die Funktion liefert immer das richtige Value egal was, aber , wenn die Konstruktion von Value Nebenwirkungen hat *, kann dies nicht akzeptabel sein.

Die zusätzlichen Instanzen sind im Allgemeinen kein Leistungsproblem, da die erste Überprüfung get() die meisten Aufrufe an putIfAbsent entfernt. Im Allgemeinen kann dieser Ansatz erheblich schneller als computeIfAbsent sein, weil dieser Aufruf unnötiges Sperren von Objekten durchführt, wenn das Objekt bereits vorhanden ist. Lokal habe ich es als 5 mal schneller gemessen, wenn da einige Objekte stark umkämpft sind.

Wenn Sie wirklich das Rechenverhalten müssen in die Karte integriert (mit einer internen Sperre gehalten so genau einem Thread das neue Objekt erzeugt), können Sie Guava die Verwendung CacheBuilder ein LoadingCache zu bekommen. Es ist im Wesentlichen das gleiche Verhalten wie Java 8 CHM, aber mit einer Tonne zusätzlicher Konfigurationsoptionen.