javajava-8parallel-processingjava-streamparallelstream

List of Strings is not running in parallel - Java 8 parallel streams


I got a requirement to run a collection using parallel stream and it is always running in sequence, here in the below example List is always running in sequence where as IntStream is running in parallel. could some please help me to understand the difference between running a parallel Stream on IntStream and parallel Stream on List<String>.

Also, can you help with the code snippet how to run List<String> in parallel similar to how IntStream is running parallel?

import java.util.List;
import java.util.stream.IntStream;

public class ParallelCollectionTest {

    public static void main(String[] args) {

        System.out.println("Parallel int stream testing.. ");
        IntStream range2 = IntStream.rangeClosed(1, 5);
        range2.parallel().peek(t -> {
            System.out.println("before");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).forEachOrdered(System.out::println);

        System.out.println("Parallel String collection testing.. ");
        List<String> list = List.of("a","b","c","d");
        list.stream().parallel().forEachOrdered(o ->
                {
                    System.out.println("before");
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(o);
                });
    }

}

output of the above code is below.

Parallel int stream testing.. 
before
before
before
before
before
1
2
3
4
5
Parallel String collection testing.. 
before
a
before
b
before
c
before
d


Solution

  • The different behavior is not caused by the different streams (IntStream vs. Stream<String>).

    The logic of your two stream pipelines is not the same.

    In the IntStream snippet you are performing the sleep in the peek() call, which allows it to run in parallel for different elements, which is why that pipeline ends quickly.

    In the Stream<String> snippet you are performing the sleep in the forEachOrdered, which means the sleep() for each element must be performed after the sleep() of the previous element ends. That's the behavior of forEachOrdered - This operation processes the elements one at a time, in encounterorder if one exists.

    You can make the second snippet behave similar to the first if you add a peek() call to it:

    System.out.println("Parallel String collection testing.. ");
    List<String> list = List.of("a","b","c","d","e","f","g","h");
    list.stream().parallel().peek(t -> {
        System.out.println("before");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    })
    .forEachOrdered(System.out::println);
    

    Now it will produce:

    Parallel String collection testing.. 
    before
    before
    before
    before
    a
    b
    c
    d