Java 8 Parallel Streams Example

Java 8 Parallel Streams Example thumbnail
56K
By Dhiraj 24 May, 2017

When it comes to stream in Java 8, there are 2 different types of stream operation available. They are sequential stream and parallel stream. In this article, we will be discussing about parallel stream in java 8. We will look into different examples of using parallel stream, differences between them, performance improvement with parallel stream and also discuss some aspects of using parallel stream.

What is Parallel Stream

Parallel stream enables parallel computing that involves processing elements concurrently in parallel with each element in a seperate thread. But this does not guarantee high performance and faster execution everytime. It again depends on the number of CPU cores available.

With parallel stream, you can partition the workload of a larger operation on all the available cores of a computer multicore processor and keep them equally busy.

Parallelstream has a much higher overhead compared to a sequential one. Parallel stream should be used only when there is a huge amount of elements to process and there is a performance problem with processing these elements. Also the parallel stream operations should be independent.

 Other Interesting Posts
Java 8 Lambda Expression
Java 8 Stream Operations
Java 8 Datetime Conversions
Java 9 Modularity Features

Creating Parallel Streams

We can create a parallel stream from an existing stream by using parallel(). Following is an example:

Stream stream = Stream.of("John", "Mike", "Ryan","Donald", "Matthew");
Stream parallelStream = stream.parallel();

Another way to create parallelstream is using parallelStream() method.

Stream parallelStream = Arrays.asList("John", "Mike", "Ryan","Donald", "Matthew").parallelStream();

Parallel Stream Example

Following is an example using parallel stream that counts number of prime numbers between 1 and 50.Stream of numbers is created by a range method and then the stream is converted to parallel stream.

public void count() {
	final long count = IntStream.range(1, 50)
            .parallel()
            .filter(number -> isPrime(number)).count();
    System.out.println("Count - " + count);
}
 
public boolean isPrime(final int number) {
    return number > 1
            && IntStream.rangeClosed(2, (int) Math.sqrt(number)).noneMatch(
                    divisor -> number % divisor == 0);
}

Output : Count - 15

Serial vs Parallel Stream Processing

If we use serial stream the order is guaranted as below:

Stream.of("John", "Mike", "Ryan","Donald", "Matthew").forEach(System.out::println);

Output:

John
Mike
Ryan
Donald
Matthew

Whereas, the order is not guaranted while using parallel stream.

Stream.of("John", "Mike", "Ryan","Donald", "Matthew").parallel().forEach(System.out::println);

Output:

Ryan
Mike
Matthew
John
Donald

Calling the method parallel on a sequential stream does not imply any concrete transformation on the stream. Internally, a bolean flag is set to signal whether the operations after the stream to be performed parallely or sequentially.

Perform Check with Parallel Stream Processing

Parallel stream providdes significant performance improvement for larger streams. Following is an example that processes large streams and compares the time difference between processing time of sequential stream and parallel stream.

ParallelStreamPerformanceCheck.java
package com.devglan;

import java.util.ArrayList;
import java.util.List;

/**
 * @author only2dhir
 *
 */
public class ParallelStreamPerformanceCheck {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List<Integer> numList = new ArrayList<Integer>();
        for (int i = 0; i < 1000; i++) {
        	numList.add(i);
        }
 
        // Processing sequentially
        long startTime = System.currentTimeMillis();
        numList.stream().forEach(i -> processData(i));
        long endTime = System.currentTimeMillis();
        double sequentialStreamTimetaken = (endTime - startTime) / 1000;
        System.out.println("Time required with stream() : " + sequentialStreamTimetaken);
 
        // Parallel processing 
        startTime = System.currentTimeMillis();
        numList.parallelStream().forEach(i -> processData(i));
        endTime = System.currentTimeMillis();
        long parallelStreamTimetaken = (endTime - startTime) / 1000;
        System.out.println("Time required with parallelStream() : " + parallelStreamTimetaken);
        System.out.println("Differential time : " + (sequentialStreamTimetaken - parallelStreamTimetaken));
    }
 
    private static void processData(int num) {
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
	}


}

Output
Time required with stream() : 11.0
Time required with parallelStream() : 2
Differential time : 9.0

Parallel stream operations such as limit and findFirst that rely on the order of the elements are expensive whereas findAny performs better than findFirst because it isn't constrained to operate in the encounter order.

While using parallel stream, an ArrayList can be split much more efficiently than a LinkedList, because the first can be evenly divided without traversing it.

Conclusion

I hope this article served you that you were looking for. If you have anything that you want to add or share then please share it below in the comment section.

Share

If You Appreciate This, You Can Consider:

We are thankful for your never ending support.

About The Author

author-image
A technology savvy professional with an exceptional capacity to analyze, solve problems and multi-task. Technical expertise in highly scalable distributed systems, self-healing systems, and service-oriented architecture. Technical Skills: Java/J2EE, Spring, Hibernate, Reactive Programming, Microservices, Hystrix, Rest APIs, Java 8, Kafka, Kibana, Elasticsearch, etc.

Further Reading on Java 8