How does reduce() method work with parallel streams in Java 8?
Asked Answered
A

1

6

I try to understand how reduce() method works exactly with parallel streams and I don't understand why the following code do not return the concatenation of these strings.

This is the code:

public class App {

    public static void main(String[] args) {
        String[] grades = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K"};

        StringBuilder concat = Arrays.stream(grades).parallel()
                .reduce(new StringBuilder(),
                        (sb, s) -> sb.append(s),
                        (sb1, sb2) -> sb1.append(sb2));

        System.out.println(concat);

    }
}

The code works only with sequential streams, but with parallel streams it doesn't return the concatenation. The output is different every time. Can someone explain me what's happening there?

Ahearn answered 7/5, 2019 at 13:13 Comment(5)
https://mcmap.net/q/142032/-java-8-streams-collect-vs-reduce/2711488docs.oracle.com/javase/8/docs/api/java/util/stream/…Thetisa
Well the first thread to get to the reduce stage gets treated first :) if you await a sequential result, you better be using a sequential stream, or at least make it sequential before the reduce operation..Spark
It’s different every time because “parallel” means multiple threads executing at the same time. Running at the same time means they do not execute in order.Eugenle
@Eugenle I understand that parallel menas multiple threads, but if instead of reduce() I'm using collect() it works perfectly even with parallel stream.Ahearn
that is the point - one is mutable reduction and the other is not. you are using reduce like it's a mutable one, and it's not. hint: accumulator and combiner must return a new instance of StringBuilder, all the time.Mirella
G
7

The problem lies in the fact you use Stream::reduce for mutable reduction. You should use Stream::collect instead that can be used for safe parallel processing. You may read more about their differences in the official Oracle documentation: Streams: Reduction.

Unlike the reduce method, which always creates a new value when it processes an element, the collect method modifies or mutates an existing value.

Notice the differences in the Javadocs for the two methods:

Therefore, I suggest you do the following:

StringBuilder concat = Arrays.stream(grades)
    .parallel()
    .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append);
Gladwin answered 8/5, 2019 at 19:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.