ArrayList
not syncing. An attempt to add items to it at the same time is not defined. From forEach
:
For parallel stream pipelines, this operation does not guarantee respect for the order in which the stream is called, since it will benefit parallelism. For any given element, an action can be performed at any time and in any thread that the library selects .
In your second example, you get multiple threads calling add
in the list of arrays at the same time, and the ArrayList
documentation says:
Please note that this implementation is not synchronized. If multiple threads access the ArrayList instance at the same time, and at least one of the threads modifies the list structurally, it must be synchronized from the outside.
Wrong decision
If you change the use of ArrayList
to Vector
, you will get the correct result, because this list implementation is synchronized. His Javadok says:
Unlike new collection implementations, Vector
synchronized.
However, do not use it! In addition, it may be slower due to explicit synchronization.
The right approach
Explicitly avoiding this situation is that the Stream API provides mutable reduction using collect
. Following
List<String> values = list.stream().map(i -> "foo").collect(Collectors.toList());
will always provide the correct result, regardless of whether it runs in parallel or not. The Stream pipeline internally handles concurrency and ensures that it is safe to use a non-competitive collector in the parallel stream collection operation . Collectors.toList()
is a built-in collector that accumulates the elements of a stream into a list.
source share