Why should I use concurrent characteristic in parallel stream with collect:
List list =
Collections.synchronizedList(new ArrayList<
Because of this : "Memory consistency effects: As with other concurrent collections, actions in a thread prior to placing an object into a ConcurrentMap as a key or value happen-before actions subsequent to the access or removal of that object from the ConcurrentMap in another thread."
These two collectors operate in a fundamentally different way.
First, the Stream framework will split the workload into independent chunks that can be processed in parallel (that’s why you don’t need a special collection as source, synchronizedList
is unnecessary).
With a non-concurrent collector, each chunk will be processed by creating a local container (here, a Map
) using the Collector’s supplier and accumulating into the local container (putting entries). These partial results have to be merged, i.e. one map has be put into the other, to get a final result.
A concurrent collector supports accumulating concurrently, so only one ConcurrentMap
will be created and all threads accumulate into that map at the same time. So after completion, no merging step is required, as there is only one map.
So both collectors are thread safe, but might exhibit entirely different performance characteristics, depending on the task. If the Stream’s workload before collecting the result is heavy, the differences might be negligible. If, like in your example, the is no relevant work before the collect operation, the outcome heavily depends on how often mappings have to be merged, i.e the same key occurs, and how the actual target ConcurrentMap
deals with contention in the concurrent case.
If you mostly have distinct keys, the merging step of a non-concurrent collector can be as expensive as the previous putting, destroying any benefit of the parallel processing. But if you have lots of duplicate keys, requiring merging of the values, the contention on the same key may degrade the concurrent collector’s performance.
So there’s no simple “which is better” answer (well, if there was such an answer, why bother adding the other variant). It depends on your actual operation. You can use the expected scenario as a starting point for selecting one, but should measure with the real life data then. Since both are equivalent, you can change your choice at any time.
First of all I gave a +1 to Holger's answer, it is a good one. I would try to simply it just a bit, by saying that :
CONCURRENT -> multiple threads throw data at the same container in no particular order (ConcurrentHashMap)
NON-CONCURRENT -> multiple threads combine their intermediate results.
The easiest way to understand it (IMHO) is to write a custom collector and play with each of it's methods: supplier, accumulator, combiner.
This was already sort-of covered here