I am trying to improve the performance of the spring applications which invokes about 8-10 queries and combined it will take about 15 to 120 seconds depending on the amount of data it queries for, i'm proposing a CompletableFuture / Future way of doing it in the Java 8. But, i have been stuck at the point where the main thread does not wait for the async threads to be completed. Thefollowing is the code which I have implemented so far.
I've contemplated to go back and implement it using the 'Future' and ThreadPoolExecutor and have a thread that waits for the completion of the spawned callable threads in the threadPoolExecutor to return the data.
Question: Any easy way to implement the CompletableFuture in java and the main thread waits for all the threads in the thread pool to be completed before returning the data to the client?
InvokeCallable .java
package net.sampleSpring.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;
@Component
public class InvokeCallable {
@Autowired
private ApplicationContext context;
// @Autowired
// @Qualifier("threadPoolExecutor")
// private ThreadPoolTaskExecutor executorThreadPool;
public void invokeCallables() throws InterruptedException, ExecutionException {
List<CompletableFuture<Integer>> lst = new ArrayList<>();
CallableOne callableOne = context.getBean(CallableOne.class);
CallableTwo callableTwo = context.getBean(CallableTwo.class);
CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
try {
return callableOne.call();
} catch (Exception e) {
e.printStackTrace();
}
return 1;
}
}
);
CompletableFuture<String> completableFuture2 = CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
try {
return callableTwo.call();
} catch (Exception e) {
e.printStackTrace();
}
return "1";
}
}
);
CompletableFuture.allOf(completableFuture1, completableFuture2).thenApply(
i -> {
System.out.println("Completed running the futures");
System.out.println("future 1" + completableFuture1.join().toString());
System.out.println("future 2" + completableFuture2.join().toLowerCase());
return i;
}
);
}
}
CallableTwo.java
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.util.concurrent.Callable;
@Component
@Scope("prototype")
public class CallableTwo {
public String call() throws Exception {
Thread.sleep(2000);
return "1000";
}
}
CallableOne.java
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("prototype")
public class CallableOne {
public Integer call() throws Exception {
Thread.sleep(2000);
return 1;
}
}
sampleSpringResource.java Code that invokes the InvokeCallable.java using restful service
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import java.util.concurrent.ExecutionException;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static org.json.XMLTokener.entity;
/* ItemValue Web service
*
*/
@Path("/")
@Service
public class sampleSpringResource {
@Inject
private InvokeCallable callable;
private static final Logger LOG = LogManager.getLogger();
@GET
@Path("/changeme/")
@Produces(APPLICATION_JSON)
public Response getsampleSpring() throws ExecutionException, InterruptedException {
callable.invokeCallables();
}
}