I have a ConcurrentHashMap
accumulating some changes which should be periodically sent somewhere (for a sort of replication). Concerning the changes, only the most recent value for any key matters.
So I need to get and remove some snapshot. The snapshot needn't be atomic, it's enough when each its entry reflects the state of the original map at some instant during the operation.
The important part is that only the entries which are present and up to date in the result may be removed from the original map. I guess, the following should do:
<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;
}
Is this really correct? Is it possible in a single iteration?
You can use the method remove(Object key, Object value)
, which will only remove the entry if the value is up-to-date, and the operation is atomic.
So this is what I suggest:
<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));
}