0

Why would the parallel stream use the combiner class, while the sequential stream would use the accumulator? Why does the parallel stream not use the accumulator?

package Streams;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class Collect
{
    public static class Debug
    {
        public static void log(Object ... objects)
        {
            for(Object object : objects) {
                System.out.println(object);
            }
        }
    }

    public static void main(String[] args)
    {
        parallel();
        Debug.log("---------------");
        sequential();
    }

    public static void parallel()
    {
        List<Integer> list = Stream.of(1,2,3,4)
                .parallel()
                .collect(
                        ArrayList::new,
                        (a,b)-> {
                            Debug.log("From accumulator",a,b);
                            a.add(b);
                        },
                        (a,b) -> {
                            Debug.log("From combiner",a,b);
                            a.addAll(b);
                        }
                );
    }

    public static void sequential()
    {
        List<Integer> list = Stream.of(1,2,3,4)
                .collect(
                        ArrayList::new,
                        (a,b)-> {
                            Debug.log("From accumulator",a,b);
                            a.add(b);
                        },
                        (a,b) -> {
                            Debug.log("From combiner",a,b);
                            a.addAll(b);
                        }
                );
    }
}

Here is the output of the code above:

From accumulator
[]
From accumulator
From accumulator
From accumulator
[]
[]
1
4
3
[]
2
From combiner
From combiner
[3]
[1]
[4]
[2]
From combiner
[1, 2]
[3, 4]
---------------
From accumulator
[]
1
From accumulator
[1]
2
From accumulator
[1, 2]
3
From accumulator
[1, 2, 3]
4

So again, why does the sequential stream use accumulator and the parallel stream the combiner? Can't the parallel stream use the accumulator?

Naman
  • 27,789
  • 26
  • 218
  • 353
Douma
  • 2,682
  • 14
  • 23
  • Looks to me like your parallel uses both. – RealSkeptic Jun 21 '20 at 16:21
  • 3
    The `parallel` on stream makes the execution occur on different threads and that calls for the merge/combine to happen as a mandatory step, while for a sequential stream it is all under one thread, hence accumulator is sufficient at least, in this case, to perform the operation in pipeline. To understand that slightly better, you can change to `System.out.println(object + " in thread " + Thread.currentThread().getName());` – Naman Jun 21 '20 at 17:03
  • 2
    Accumulator adds one item, e.g. PartialResult + StreamItem. Combiner combines two partial results, e.g. PartialResult + PartialResult. Imagine your collector is making a List. An accumulator adds one item to a List: List + Item. A combiner merges two Lists: List + List – Michael Jun 21 '20 at 17:11

1 Answers1

0

The combiner's job seems to be to combine the different List-objects created for each thread (with parallel).

    public static void parallel()
    {
        List<Integer> list = Stream.of(1,2,3,4)
                .parallel()
                .collect(
                        ArrayList::new,
                        (a,b)-> {
                            Debug.log("From accumulator",a,b);
                            a.add(b);
                        },
                        (a,b) -> {
                            Debug.log("From combiner",a,b);
                            a.addAll(b);
                        }
                );
    }

So in the example above, for 1,2,3,4 a new ArrayList is created for each element, because they run parallel on a different thread. So the combiner combines the 4 existing ArrayLists into one.

Douma
  • 2,682
  • 14
  • 23
  • 1
    The phrase “seems to be” suggests that you are making guesswork, which raises the question why you don’t start with reading [the class documentation](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#collect-java.util.stream.Collector-), [the package documentation](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#MutableReduction), or [the tutorial](https://docs.oracle.com/javase/tutorial/collections/streams/reduction.html#collect) instead. – Holger Jun 22 '20 at 11:09