Ich muss wissen, wenn ich einen Synchronisierungsblock zu meinem Code hinzufügen sollte, wenn Sie ConcurrentHashMap verwenden. Sagen wir, ich habe eine Methode wie:Wann und wie sollte ich zusätzliche Synchronisation von ConcurrentHashMap verwenden?
private static final ConcurrentMap<String, MyObjectWrapper> myObjectsCache = new ConcurrentHashMap<>(CACHE_INITIAL_CAPACITY);
public List<MyObject> aMethod(List<String> ids, boolean b) {
List<MyObject> result = new ArrayList<>(ids.size());
for (String id : ids) {
if (id == null) {
continue;
}
MyObjectWrapper myObjectWrapper = myObjectsCache.get(id);
if (myObjectWrapper == null) {
continue;
}
if (myObjectWrapper.getObject() instanceof MyObjectSub) {
((MyObjectSub) myObjectWrapper.getObject()).clearAField();
myObjectWrapper.getObject().setTime(System.currentTimeMillis());
}
result.add(myObjectWrapper.getObject());
if (b) {
final MyObject obj = new MyObject(myObjectWrapper.getObject());
addObjectToDb(obj);
}
}
return result;
}
Wie soll ich effizient diese Methode gleichzeitig machen? Ich denke, dass die "Get" ist sicher, aber sobald ich den Wert aus dem Cache und aktualisieren Sie die Felder des zwischengespeicherten Objekts - es kann Probleme geben, weil ein anderer Thread den gleichen Wrapper bekommen könnte und versuchen, das zugrunde liegende Objekt zu aktualisieren ... Sollte ich Synchronisation hinzufügen? Und wenn ja, sollte ich dann von "get" bis zum Ende der Schleifeniteration oder der gesamten Schleife synchronisieren?
Vielleicht könnte jemand einige spezifischere Leitlinien der ordnungsgemäßen und effizienten Nutzung von ConcurrentHashMap teilen, wenn einige weitere Operationen auf der Karte Schlüssel/Werte innerhalb von Schleifen usw. gemacht werden müssen ...
Ich würde wirklich dankbar sein.
EDIT: Einige Kontext für die Frage: arbeite ich zur Zeit auf Refactoring einiger dao Klassen in Produktionscode und einige der Klassen aus der Datenbank abgerufen HashMaps für das Caching von Daten verwendet. Alle Methoden, die den Cache nutzten (zum Schreiben oder Lesen), hatten ihren gesamten Inhalt in einem synchronisierten (Cache-) Block (spielen sicher?). Ich habe nicht viel Erfahrung mit Nebenläufigkeit und ich möchte diese Gelegenheit wirklich nutzen, um zu lernen. Ich habe naiv die HashMaps in ConcurrentHashMaps geändert und möchte nun die synchronisierten Bloocks dort entfernen, wo sie benötigt werden. Alle Caches werden zum Schreiben und Lesen verwendet. Die vorgestellte Methode basiert auf einer der Methoden, die ich geändert habe, und jetzt versuche ich zu lernen, wann und in welchem Umfang ich synchronisiere. Die Methode clearAField ändert nur einen Wert eines der Felder des umbrochenen POJO-Objekts, und addObjectToDb versucht, das Objekt der Datenbank hinzuzufügen.
Ein anderes Beispiel wäre der Cache werden Nachfüllen:
public void findAll() throws SQLException{
// get data from database into a list
List<Data> data=getAllDataFromDatabase();
cacheCHM.clear();
cacheCHM.putAll(data);
}
In dem Fall, dass ich die klare und putAll in einem synchronize (cacheCHM) Block, rechts setzen sollte?
Ich habe versucht, finden und einige Beiträge/Artikel über die richtige und effiziente Nutzung von CHM, aber die meisten handeln von Einzeloperationen, ohne Schleifen usw. lesen .... Das beste was ich gefunden habe, seien: http://www.javamadesoeasy.com/2015/04/concurrenthashmap-in-java.html
Es hängt ziemlich von Ihrer Anwendungslogik ab. – pintxo
Wenn Sie eine Aktualisierung des abgerufenen Werts als threadsicher durchführen müssen, müssen Sie die Synchronisierung für das Objekt selbst durchführen. 'ConcurrentHashMap' schützt nur die Struktur der Map selbst (dh die Beziehung von Schlüsseln zu Werten), nicht die enthaltenen Werte. –
Ich stimme mit @Jim überein, gleichzeitige Karte schützt nur die Struktur (d. H. Beziehung von Schlüsseln zu Werten). Ich möchte noch eine weitere Sache hinzufügen. Laut dem obigen Code-Kontext lesen Sie nur den Wert ie.e myObjectsCache.get (id), so dass Sie zu diesem Zweck sogar keine Concurrent-Map benötigen, bis Sie anrufen map.put(). – pbajpai21