depending on the situation, one does not lose all the benefits of parallelism by using ForEachOrdered.
Assume that we have something as such:
stringList.parallelStream().map(String::toUpperCase)
.forEachOrdered(System.out::println);
In this case, we can guarantee that the ForEachOrdered terminal operation will print out the strings in uppercase in the encounter order but we should not assume that the elements will be passed to the map intermediate operation in the same order they were picked for processing. The map operation will be executed by multiple threads concurrently. So one may still benefit from parallelism but it's just that we’re not leveraging the full potential of parallelism. To conclude, we should use ForEachOrdered when it matters to perform an action in the encounter order of the stream.
edit following your comment:
What happens when you skip
mapoperation? I am more interested inforEachOrderedright afterparallelStream()
if you're referring to something as in:
stringList.parallelStream().forEachOrdered(action);
there is no benefit in doing such thing and I doubt that's what the designers had in mind when they decided to create the method. in such case, it would make more sense to do:
stringList.stream().forEach(action);
to extend on your question "Why would anyone use forEachOrdered with parallel stream if we are losing parallelism", say you wanted to perform an action on each element with respect to the streams encounter order; in such case you will need to use forEachOrdered as the forEach terminal operation is non deterministic when used in parallel hence there is one version for sequential streams and one specifically for parallel streams.
depending on the situation, one does not lose all the benefits of parallelism by using ForEachOrdered.
Assume that we have something as such:
stringList.parallelStream().map(String::toUpperCase)
.forEachOrdered(System.out::println);
In this case, we can guarantee that the ForEachOrdered terminal operation will print out the strings in uppercase in the encounter order but we should not assume that the elements will be passed to the map intermediate operation in the same order they were picked for processing. The map operation will be executed by multiple threads concurrently. So one may still benefit from parallelism but it's just that we’re not leveraging the full potential of parallelism. To conclude, we should use ForEachOrdered when it matters to perform an action in the encounter order of the stream.
edit following your comment:
What happens when you skip
mapoperation? I am more interested inforEachOrderedright afterparallelStream()
if you're referring to something as in:
stringList.parallelStream().forEachOrdered(action);
there is no benefit in doing such thing and I doubt that's what the designers had in mind when they decided to create the method. in such case, it would make more sense to do:
stringList.stream().forEach(action);
to extend on your question "Why would anyone use forEachOrdered with parallel stream if we are losing parallelism", say you wanted to perform an action on each element with respect to the streams encounter order; in such case you will need to use forEachOrdered as the forEach terminal operation is non deterministic when used in parallel hence there is one version for sequential streams and one specifically for parallel streams.
I don't really get the question here. Why? because you simply have no alternative - you have so much data that parallel streams will help you (this still needs to be proven); but yet you still need to preserve the order - thus forEachOrdered. Notice that the documentation says may and not will lose that for sure - you would have to measure and see.
Videos
Stream.of("AAA","BBB","CCC").parallel().forEach(s->System.out.println("Output:"+s));
Stream.of("AAA","BBB","CCC").parallel().forEachOrdered(s->System.out.println("Output:"+s));
The second line will always output
Output:AAA
Output:BBB
Output:CCC
whereas the first one is not guaranted since the order is not kept. forEachOrdered will processes the elements of the stream in the order specified by its source, regardless of whether the stream is sequential or parallel.
Quoting from forEach Javadoc:
The behavior of this operation is explicitly nondeterministic. For parallel stream pipelines, this operation does not guarantee to respect the encounter order of the stream, as doing so would sacrifice the benefit of parallelism.
When the forEachOrdered Javadoc states (emphasis mine):
Performs an action for each element of this stream, in the encounter order of the stream if the stream has a defined encounter order.
Although forEach shorter and looks prettier, I'd suggest to use forEachOrdered in every place where order matters to explicitly specify this. For sequential streams the forEach seems to respect the order and even stream API internal code uses forEach (for stream which is known to be sequential) where it's semantically necessary to use forEachOrdered! Nevertheless you may later decide to change your stream to parallel and your code will be broken. Also when you use forEachOrdered the reader of your code sees the message: "the order matters here". Thus it documents your code better.
Note also that for parallel streams the forEach not only executed in non-determenistic order, but you can also have it executed simultaneously in different threads for different elements (which is not possible with forEachOrdered).
Finally both forEach/forEachOrdered are rarely useful. In most of the cases you actually need to produce some result, not just side-effect, thus operations like reduce or collect should be more suitable. Expressing reducing-by-nature operation via forEach is usually considered as a bad style.
Because ArrayList is not a thread-safe collection. Using a thread-safe collection like CopyOnWriteArrayList would make it correct but not necessarily efficient.
Using a Collector instead would be much simpler and correct. e.g.
source.parallelStream().collect(Collectors.toList())
The forEach operation of the parallel stream is adding elements to an un-synchronized Collection (an ArrayList) from multiple threads. Therefore, the operation is not thread safe, and has unexpected results.
Using forEachOrdered() instead of forEach() will ensure all the elements of the source List are added to the destination List.
However, as mentioned in the other answer, using collect(Collectors.toList()) is the correct way to produce an output List from a Stream.
You are right in that the guarantees made for the action of forEachOrdered only apply to that action and nothing else. But it’s wrong to assume that this is the same as .sequential().forEach(…).
sequential will turn the entire stream pipeline into sequential mode, thus, the action passed to forEach will be executed by the same thread, but also the preceding peek’s action. For most intermediate operations, the exact placement of parallel or sequential is irrelevant and specifying both makes no sense as only the last one will be relevant.
Also, there is still no guaranty made about the ordering when using forEach, even if it hasn’t any consequences in the current implementation. This is discussed in “Does Stream.forEach respect the encounter order of sequential streams?”
The documentation of Stream.forEachOrdered states:
This operation processes the elements one at a time, in encounter order if one exists. Performing the action for one element happens-before performing the action for subsequent elements, but for any given element, the action may be performed in whatever thread the library chooses.
So the action may get invoked by different threads, as perceivable by Thread.currentThread() but not run concurrently.
Further, if the stream has an encounter order, it will get reconstituted at this place. This answer sheds some light one the difference of encounter order and processing order.
The #3 code is not conceptually equivalent to #1, because parallel() or sequential() calls affect the whole stream, not just the subsequent operations. So in #3 case the whole procedure will be performed sequentially. Actually #3 case resembles the early design of the Stream API when you actually could change the parallel/sequential mode. This was considered to be unnecessary complication (and actually added problems, see, for example, this discussion) as usually you only need to change mode to make the terminal operation ordered (but not necessarily sequential). So forEachOrdered() was added and parallel()/sequential() semantics was changed to affect the whole stream (see this changeset).
Basically you're right: in parallel stream there's no order guarantee for intermediate operations. If you need to perform them in particular order, you have to use the sequential stream.