Java 8 Parallel Streams Example
Hello readers, Parallel Streams are the greatest addition to Java8 after Lambdas. This tutorial explains the parallel streams concept in detail.
1. Introduction
The Stream API enables developers to create the parallel streams that can take advantage of multi-core architectures and enhance the performance of Java code. In a parallel stream, the operations are executed in parallel and there are two ways to create a parallel stream.
- Using the
parallelStream()
method on a collection - Using the
parallel()
method on a stream
E.g.
Optional<Integer> calcProd = list1.parallelStream().reduce((a,b) -> a*b));
In this code, a parallel stream is obtained from the list1
and the reduction operation is performed on it.
Do remember, Parallel Streams must be used only with stateless, non-interfering, and associative operations i.e.
- A stateless operation is an operation in which the state of one element does not affect another element
- A non-interfering operation is an operation in which data source is not affected
- An associative operation is an operation in which the result is not affected by the order of operands
1.1 Parallel Streams in Java 8
Let’s take a scenario where you have a list of employee objects and you have to count the employees whose salary is above 15000. Generally, to solve this problem you will iterate over list going through each employee and checking if employee’s salary is above 15000. This takes O(N) time since you go sequentially.
Streams give us the flexibility to iterate over the list in a parallel pattern and can give the total in quick fashion. Stream implementation in Java is by default sequential unless until it is explicitly mentioned in parallel. When a stream executes in parallel, the Java runtime partitions the stream into multiple sub-streams. Aggregate operations iterate over and process these sub-streams in parallel and then combine the results.
The only thing to keep in mind to create parallel stream is to call the parallelStream()
method on the collection else by default the sequential stream gets returned by stream()
method.
1.1.1 Parallel Streams Performance Implications
Parallel Stream has equal performance impacts as like its advantages.
- Since each sub-stream is a single thread running and acting on the data, it has overhead compared to the sequential stream
- Inter-thread communication is dangerous and takes time for coordination
1.2 When to use Parallel Streams?
- They should be used when the output of the operation is not needed to be dependent on the order of elements present in source collection (i.e. on which the stream is created)
- Parallel Streams can be used in case of aggregate functions
- Parallel Streams quickly iterate over the large-sized collections
- Parallel Streams can be used if developers have performance implications with the Sequential Streams
- If the environment is not multi-threaded, then Parallel Stream creates thread and can affect the new requests coming in
Now, open up the Eclipse Ide and I will explain further the parallel streams in Java8 programming.
2. Java8 Parallel Streams Example
2.1 Tools Used
We are using Eclipse Oxygen, JDK 1.8 and Maven.
2.2 Project Structure
Firstly, let’s review the final project structure, in case you are confused about where you should create the corresponding files or folder later!
2.3 Project Creation
This section will show on how to create a Java-based Maven project with Eclipse. In Eclipse IDE, go to File -> New -> Maven Project
.
In the New Maven Project window, it will ask you to select project location. By default, ‘Use default workspace location’ will be selected. Select the ‘Create a simple project (skip archetype selection)’ checkbox and just click on next button to go ahead.
It will ask you to ‘Enter the group and the artifact id for the project’. We will input the details as shown in the below image. The version number will be by default: 0.0.1-SNAPSHOT
.
Click on Finish and the creation of a maven project is completed. If you see, it has downloaded the maven dependencies and a pom.xml
file will be created. It will have the following code:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>Java8ParallelStream</groupId> <artifactId>Java8ParallelStream</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> </project>
Developers can start adding the dependencies that they want. Let’s start building the application!
3. Application Building
Below step is involved in developing this application.
3.1 Java Class Implementation
Let’s create the required Java file. Right-click on the src/main/java
folder, New -> Package
.
A new pop window will open where we will enter the package name as: com.jcg.java
.
Once the package is created in the application, we will need to create the implementation class to illustrate the Java8 Parallel Stream example. Right-click on the newly created package: New -> Class
.
A new pop window will open and enter the file name as: ParallelStreamDemo
. The implementation class will be created inside the package: com.jcg.java
.
3.1.1 Example on Parallel Streams
Here is an example of Parallel Streams where we have created a list of 600 employees out of which there are 300 employees whose salary is above 15000. Let’s see the simple code snippet that shows this implementation.
ParallelStreamDemo.java
package com.jcg.java; import java.util.ArrayList; import java.util.List; public class ParallelStreamDemo { public static void main(String[] args) { long t1, t2; List<Employee> eList = new ArrayList<Employee>(); for(int i=0; i<100; i++) { eList.add(new Employee("A", 20000)); eList.add(new Employee("B", 3000)); eList.add(new Employee("C", 15002)); eList.add(new Employee("D", 7856)); eList.add(new Employee("E", 200)); eList.add(new Employee("F", 50000)); } /***** Here We Are Creating A 'Sequential Stream' & Displaying The Result *****/ t1 = System.currentTimeMillis(); System.out.println("Sequential Stream Count?= " + eList.stream().filter(e -> e.getSalary() > 15000).count()); t2 = System.currentTimeMillis(); System.out.println("Sequential Stream Time Taken?= " + (t2-t1) + "\n"); /***** Here We Are Creating A 'Parallel Stream' & Displaying The Result *****/ t1 = System.currentTimeMillis(); System.out.println("Parallel Stream Count?= " + eList.parallelStream().filter(e -> e.getSalary() > 15000).count()); t2 = System.currentTimeMillis(); System.out.println("Parallel Stream Time Taken?= " + (t2-t1)); } }
4. Run the Application
To run the application, developers need to right-click on the class, Run As -> Java Application
. Developers can debug the example and see what happens after every step!
5. Project Demo
The application shows the following logs as output where creating a Sequential Stream and filtering elements took 178 ms
, whereas Parallel Stream only took 15 ms
.
# Logs for 'SEQUENTIAL STREAM' # ============================= Sequential Stream Count?= 300 Sequential Stream Time Taken?= 178 # Logs for 'PARALLEL STREAM' # =========================== Parallel Stream Count?= 300 Parallel Stream Time Taken?= 15
That’s all for this post. Happy Learning!
6. Conclusion
That’s all for Java8 Parallel Streams example and developers can use it to divide the provided task into many and run them in different threads. I hope this article served you whatever you were looking for.
7. Download the Eclipse Project
This was an example of Parallel Streams in Java8.
You can download the full source code of this example here: Java8ParallelStream
Really do like the functionality of Java 8 streams. I have been able to do some of the same tasks with streams that I was doing prior to Java 8 with a lot less lines of code.
The “time taken” measurements do not show anything. Try to do the parallel stream first, and the times are completely different.
Thank you, Anon! :)
The processor is caching that operation so even if you tried to do the parallel stream first, will get the same result and maybe the sequential would be faster
yeah but processor is limited to caching that operation , if u have more thank 1 operation and complexity. it will be take a time if u used sequential. remember 1 people will take a long time than 2 people .its princip.
How to know the number of threads used and can we control that?
Thanks a lot is too good. u write excellent content.
thanks. :-)
Try below code and give me your comments. public static void main(String[] args) { long t1, t2; List<Employee> eList = new ArrayList<Employee>(); for(int i=0; i<100; i++) { eList.add(new Employee(“A”, 20000)); eList.add(new Employee(“B”, 3000)); eList.add(new Employee(“C”, 15002)); eList.add(new Employee(“D”, 7856)); eList.add(new Employee(“E”, 200)); eList.add(new Employee(“F”, 50000)); } /***** Here We Are Creating A ‘Parallel Stream’ & Displaying The Result *****/ t1 = System.currentTimeMillis(); System.out.println(“Parallel Stream Count?= ” + eList.parallelStream().filter(e -> e.getSalary() > 15000).count()); t2 = System.currentTimeMillis(); System.out.println(“Parallel Stream Time Taken?= ” + (t2-t1)); /***** Here We Are Creating A ‘Sequential Stream’ & Displaying The Result *****/… Read more »