Reputation: 93
I have a scenario where I do a lot number of validations in sequence like..
public class validationClass{
public validate(ValidationObject validationObj){
validation1(validationObj);
validation2(validationObj);
validation3(validationObj);
validation4(validationObj);
...
validationN(validationObj);
return validationObj;
}
}
validationObject is passed into each validation and any errors if present will be attached into it and finally object will be returned back. Currently it is taking much more time because execution is sequential.
Can I execute the validations in parallel and merge the responses in each thread and send back?
Is it possible to achieve this by Completable Futures? I couldn't find an example for this. Please can any one give me some pointers?
Upvotes: 1
Views: 1355
Reputation: 71
Yes, it can be executed using CompletableFuture
library.
I can share you an example, try to implement the same for your problem statement.
Create a list of CompletableFuture objects that will be accepting ValidationObject type as input.
List<CompletableFuture<ValidationObject>> completableFutureList = new ArrayList<>();
Add the validation functions to the list.
completableFutureList.add(validation1(validationObj));
completableFutureList.add(validation2(validationObj));
The validation methods must return the same type (in my example : CompletableFuture). CompletableFuture does not accept void type and atleast some type must be returned. If your method does not return anything, then atleast return some String, For example : CompletableFuture. Here "asyncExecutor" is nothing but the custom @bean name we assign in the ThreadPoolTaskExecutor configuration.
More details in this link : https://www.oodlestechnologies.com/blogs/threadpooltaskexecutor-configuration-with-spring-boot/
@Async("asyncExecutor")
public CompletableFuture<String> validation1(ValidationObject validation)
{
//your code here
}
Then join the individual async tasks together, so that the executor proceeds to other parts of code only after receiving the result from all the threads. If you do not join then the other code gets executed and the validation methods in each threads execute asynchronously.
for (CompletableFuture<ValidationObject> completableFuture : completableFutureList)
{
completableFuture.join();
}
Upvotes: 1
Reputation: 1244
You can opt for java8 Streams's parallel processing
. To simulate your scenario I created some random validation functions doing some sort of processing on data.
import java.util.stream.Stream;
public class StackOverFlow_65531407 {
public static void main(String[] args) {
StackOverFlow_65531407 stack = new StackOverFlow_65531407();
ValidationObject vObj = new ValidationObject(1l, "name", "Password", "role");
Long t1 = System.currentTimeMillis();
stack.validate(vObj);
Long t2 = System.currentTimeMillis();
stack.validate_parallel(vObj);
Long t3 = System.currentTimeMillis();
System.out.println("---------------------------------------");
System.out.println("time in non-parallel execution::" + (t2 - t1) + " milliseconds");
System.out.println("time in parallel execution::" + (t3 - t2) + " milliseconds");
System.out.println("---------------------------------------");
}
public ValidationObject validate(ValidationObject validationObj) {
v1(validationObj);
v2(validationObj);
v3(validationObj);
v4(validationObj);
return validationObj;
}
public ValidationObject validate_parallel(ValidationObject validationObj) {
Stream.of(validationObj)
.parallel()
.map(this::v1)
.map(this::v2)
.map(this::v3)
.map(this::v4);
return validationObj;
}
private ValidationObject v1(ValidationObject validationObj) {
//do validation on id
if (validationObj.getId() != null) {
System.out.println(validationObj.getId());
for (int i = 0; i < 10000; i++) {
System.out.println("\tPrinted " + i);
}
}
return validationObj;
}
private ValidationObject v2(ValidationObject validationObj) {
//do validation on name
if (validationObj.getName() != null) {
System.out.println(validationObj.getName());
for (int i = 0; i < 10000; i++) {
System.out.println("\tPrinted " + i);
}
}
return validationObj;
}
private ValidationObject v3(ValidationObject validationObj) {
//do validation on password
if (validationObj.getPassword() != null) {
System.out.println(validationObj.getPassword());
for (int i = 0; i < 10000; i++) {
System.out.println("\tPrinted " + i);
}
}
return validationObj;
}
private ValidationObject v4(ValidationObject validationObj) {
//do validation on role
if (validationObj.getRole() != null) {
System.out.println(validationObj.getPassword());
for (int i = 0; i < 1000; i++) {
System.out.println("\tPrinted " + i);
}
}
return validationObj;
}
}
For smaller number of inputs(like printing till 100s or thousands), stream parallel will be slow. But in a larger picture, stream out run the sequential processing.
I had the output as:
----
---
Printed 987
Printed 988
Printed 989
Printed 990
Printed 991
Printed 992
Printed 993
Printed 994
Printed 995
Printed 996
Printed 997
Printed 998
Printed 999
---------------------------------------
time in non-parallel execution::249 milliseconds
time in parallel execution::96 milliseconds
---------------------------------------
You can see how parallel stream significantly reduced your time. But it's also an opinionated choice to use parallel stream.
Upvotes: 0