2017-11-05 5 views
1

Ich habe eine ConcurrentHashMap akkumuliert einige Änderungen, die in regelmäßigen Abständen irgendwo gesendet werden sollten (für eine Art der Replikation). Bei den Änderungen ist nur der letzte Wert für einen Schlüssel von Bedeutung.Holen und entfernen Sie alle aktuellen Einträge von einer ConcurrentMap

Also muss ich einige Schnappschüsse bekommen und entfernen. Der Snapshot muss nicht atomar sein, es reicht aus, wenn jeder seiner Einträge den Status der ursprünglichen Map während des Vorgangs in einem bestimmten Moment wiedergibt.

Der wichtige Teil ist, dass nur die Einträge, die im Ergebnis vorhanden und aktuell sind, aus der ursprünglichen Karte entfernt werden können. Ich schätze, folgendes sollte tun:

<K, V> ConcurrentMap<K, V> getAndRemoveAll(ConcurrentMap<K, V> map) { 
    ConcurrentHashMap<K, V> result = new ConcurrentHashMap<>(map);  
    result.forEach((resultKey, resultValue) -> 
    map.computeIfPresent(resultKey, 
     (k, mapValue) -> mapValue==resultValue ? null : mapValue)); 
    return result; 
} 

Ist das wirklich richtig? Ist es in einer einzigen Iteration möglich?

+0

@JoeC es wäre, wenn der Code korrekt funktioniert, aber ich bin ziemlich sicher, dass es nicht ist. OP vergleicht Objekte mit '==', was im Allgemeinen nicht korrekt funktioniert. – Turing85

+0

@JoeC Die vier Zeilen sind nichts anderes als eine Beschreibung dessen, was es tun sollte, nicht wirklich etwas zu überprüfen. – maaartinus

+0

@ Turing85 Das Verwenden von '==' ist hier wahrscheinlich in Ordnung, denn wenn ein Wert durch einen anderen ersetzt wird, der nicht derselbe ist, aber 'equals', dann wird ein Wert unnötigerweise in der Karte bleiben gelassen. Es ist korrekt in dem Sinne, dass es nicht (genau) der Wert ist, der im Ergebnis vorhanden ist, was bedeutet, dass die Karte sich geändert hat, nachdem der Schnappschuss gemacht wurde. – maaartinus

Antwort

2

Sie können die Methode remove(Object key, Object value) verwenden, die nur den Eintrag entfernt, wenn der Wert aktuell ist, und der Vorgang ist atomar.

So ist es das, was ich vorschlagen:

<K, V> Map<K, V> getAndRemoveAll(ConcurrentMap<K, V> map) { 
    return map.entrySet().stream() 
    .filter(e -> map.remove(e.getKey(), e.getValue())) 
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); 
} 
Verwandte Themen