Calling two Java methods asynchronously [duplicate] - java

This question already has answers here:
How to asynchronously call a method in Java
(12 answers)
Closed 5 years ago.
I have the following code that is making a call to two web services. Both web services return very large responses, so the response is taking quite a long time to return (one web service request is 8 seconds, the other is 12 seconds). The total execution time is 20 seconds as the requests are running in series and not parallel.
Is there any way I can modify my code to request the two web services asynchronously and be able to get the response processed in a time closer to 12 seconds than 20 seconds that it currently takes?
String listOfCities;
String listOfCountries;
try {
listOfCities = service.getListOfCities(host+"service/cities");
listOfCountries = service.getListOfCountries(host+"service/countries");
} catch (Exception e) {
log.error("Failed to read service: " + e);
}
** Thanks for the responses, I feel this isn't a duplicate as I wanted to stop the execution of the two threads I was executing until both received a result from both. The solutions below show that. **

I would try something simple, like CompletableFuture:
import java.util.concurrent.CompletableFuture;
...
final CompletableFuture<String> listOfCities = CompletableFuture.supplyAsync(() -> service.getListOfCities(...));
final CompletableFuture<String> listOfCountries = CompletableFuture.supplyAsync(() -> service. getListOfCountries(...));
final CompletableFuture<Void> allCompleted = CompletableFuture.allOf(listOfCities, listOfCountries);
allCompleted.thenRun(() -> {
// whatever you want to do
});
See these examples for reference.

very simple implementation, For more advance you may want to take look at FutureTask
List<Thread> threadList = new ArrayList<>();
threadList.add(new Thread(new Runnable() {
#Override
public void run() {
try {
listOfCountries = service.getListOfCountries(host+"service/countries");
} catch (Exception e) {
log.error("Failed to read service: " + e);
}
}
}));
threadList.add(new Thread(new Runnable() {
#Override
public void run() {
try {
listOfCities = service.getListOfCities(host+"service/cities");
} catch (Exception e) {
log.error("Failed to read service: " + e);
}
}
}));
for (Thread t:threadList ){
t.start();
}
for (Thread t:threadList ){
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//after both finish proceeds from here
Note the Strings Should be defined more globally (class level, not local variables)

Global variables of the class.
String listOfCities;
String listOfCountries;
In the function, the methods would be called like this,
try {//t is the object of the class like (Test t = new Test();)
new Thread(()-> t.listOfCities = service.getListOfCities(host+"service/cities");).start();
new Thread(()-> t.listOfCountries = service.getListOfCountries(host+"service/countries");).start();
} catch (Exception e) {
log.error("Failed to read service: " + e);
}
Code example https://ideone.com/wB9SMa
By #AniketSahrawat

If you want the execution time in completion order I would advice you to use ListenableFuture from guava. Futures.inCompletionOrder will do the job.
Sample usage can look something like that:
ExecutorService es;
Callable<String> task1;
Callable<String> task2;
//...
ListeningExecutorService listeningExecutorService = MoreExecutors.listeningDecorator(es);
List<ListenableFuture<String>> yourTasks = new ArrayList<>();
yourTasks.add(listeningExecutorService.submit(task1));
yourTasks.add(listeningExecutorService.submit(task2));
for(Future f: Futures.inCompletionOrder(yourTasks)){
//process your task in completion order now
}

Related

In Java, how to test a private code running in parallel with executor service wrapped in public method

I had an existing non-parallel code that we recently made concurrent by using executor service. Adding concurrency ensured limit the number of requests sent to another API in our scenario. So we are calling an external service and limiting requests, waiting for all requests to complete so as merge the responses later before sending the final response.
I am stuck on how to add a unit test/mock test to such a code, considering the private method is parallelized. I have added below my code structure to explain my situation.
I am trying to test here
#Test
public void processRequest() {
...
}
Code
int MAX_BULK_SUBREQUEST_SIZE = 10;
public void processRequest() {
...
// call to private method
ResponseList responseList = sendRequest(requestList);
}
private void sendRequest(List<..> requestList) {
List<Response> responseList = new ArrayList<>();
ExecutorService executorService = Executors.newFixedThreadPool(10);
int numOfSubRequests = requestList.size();
for (int i = 0; i < numOfSubRequests; i += MAX_BULK_SUBREQUEST_SIZE) {
List<Request> requestChunk;
if (i + MAX_BULK_SUBREQUEST_SIZE >= numOfSubRequests) {
requestChunk = requestList.subList(i, numOfSubRequests);
} else {
requestChunk = requestList.subList(i, i + MAX_BULK_SUBREQUEST_SIZE);
}
// parallelization
executorService.submit(() -> {
Response responseChunk = null;
try {
responseChunk = callService(requestChunk); // private method
} catch (XYZException e) {
...
try {
throw new Exception("Internal Server Error");
} catch (Exception ex) {
...
}
}
responseList.add(responseChunk);
});
}
executorService.shutdown();
try {
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
} catch (InterruptedException e) {..}
}
return responseList;
}
private Response callService(..) {
// call to public method1
method1(..);
// call to public method2
method2(..);
}
I was able to do so with unit tests and adding a mockito verify on how many times a method is called. If it's running in parallel after chunkifying, then the method will be called more than once equal to number of chunks it's going to process.

Java 8 completable future to execute methods parallel

I have 3 methods that I need to run in parallel, since they are independent to each other and combine the results of each one at the end and send it as the response. I need to handle exception as well.
In different post I found the below code and modified accordingly.
public Response getResponse() {
Response resultClass = new Response();
try {
CompletableFuture<Optional<ClassA>> classAFuture
= CompletableFuture.supplyAsync(() -> service.getClassA() );
CompletableFuture<ClassB> classBFuture
= CompletableFuture.supplyAsync(() -> {
try {
return service.getClassB();
}
catch (Exception e) {
throw new CompletionException(e);
}
});
CompletableFuture<ClassC> classCFuture
= CompletableFuture.supplyAsync(() -> {
try {
return service.getClassC();
} catch (Exception e) {
throw new CompletionException(e);
}
});
CompletableFuture<Response> responseFuture =
CompletableFuture.allOf(classAFuture, classBFuture, classCFuture)
.thenApplyAsync(dummy -> {
if (classAFuture.join().isPresent() {
ClassA classA = classAFuture.join();
classA.setClassB(classBFuture.join());
classA.setClassC(classCFuture.join());
response.setClassA(classA)
}
return response;
});
responseFuture.join();
} catch (CompletionExecution e) {
throw e;
}
return response;
}
Should the above run correctly in parallel? I see it takes some more time, and I wanted to make sure I am doing it right.
If you want to run methods in parallel you should use ExecutorService. Try something like that:
ExecutorService myExecutor = Executors.newFixedThreadPool(3);
List<Future<Object>> futures = myExecutor.invokeAll(
Arrays.asList(
() -> service.getClassA(),
() -> service.getClassB(),
() -> service.getClassC(),
)
);
myExecutor.shutdown();
The idea is correct, but this all could be done with a lot less code:
public Response getResponse() {
CompletableFuture<Optional<ClassA>> classAFuture = CompletableFuture.supplyAsync(() -> service.getClassA());
CompletableFuture<ClassB> classBFuture = CompletableFuture.supplyAsync(() -> service.getClassB());
CompletableFuture<ClassC> classCFuture = CompletableFuture.supplyAsync(() -> service.getClassC());
try {
return CompletableFuture.allOf(classAFuture, classBFuture, classCFuture)
.thenApply(() -> {
Response response = new Response();
Optional<ClassA> maybeA = classAFuture.get();
if (maybeA.isPresent()) {
ClassA classA = maybeA.get();
classA.setClassB(classBFuture.get());
classA.setClassC(classCFuture.get());
response.setClassA(classA);
}
return response;
}).get();
} catch (ExecutionException e) { // Ususally the exception is wrapped to ExecutionException by java concurrency framework itself
Throwable cause = e.getCause();
if (cause != null) {
throw cause;
} else {
throw e;
}
}
}
Main things:
You don't need to wrap your exceptions to CompletionException.
You don't need to use thenApplyAsync. Just thenApply is the same thing unless you want to be very specific on the type of thread you want to use. Check this for more information https://stackoverflow.com/a/47489654/3020903
You don't need to join() anything. By the time CompletableFuture.all has finished, you can be very sure that all the supplied jobs have finished and calling get() on then will just return the value.
As for can you be sure jobs A, B and C will be run in parallel. Yes and no. It will be run in parallel if there are enough system resources to run them in parallel. You have done your best to ask them to run in parallel. Maybe at some point you also want to supply your custom thread pool to have more control, but that's a topic for another day.

Java Using CountDownLatch to poll a method until a success response

I am trying to call a method multiple times every 60 seconds until a success response from the method which actually calls a rest end point on a different service. As of now I am using do while loop and using
Thread.sleep(60000);
to make the main thread wait 60 seconds which I feel is not the ideal way due to concurrency issues.
I came across the CountDownLatch method using
CountDownLatch latch = new CountDownLatch(1);
boolean processingCompleteWithin60Second = latch.await(60, TimeUnit.SECONDS);
#Override
public void run(){
String processStat = null;
try {
status = getStat(processStatId);
if("SUCCEEDED".equals(processStat))
{
latch.countDown();
}
} catch (Exception e) {
e.printStackTrace();
}
}
I have the run method in a different class which implements runnable. Not able to get this working. Any idea what is wrong?
You could use a CompletableFuture instead of CountDownLatch to return the result:
CompletableFuture<String> future = new CompletableFuture<>();
invokeYourLogicInAnotherThread(future);
String result = future.get(); // this blocks
And in another thread (possibly in a loop):
#Override
public void run() {
String processStat = null;
try {
status = getStat(processStatId);
if("SUCCEEDED".equals(processStat))
{
future.complete(processStat);
}
} catch (Exception e) {
future.completeExceptionally(e);
}
}
future.get() will block until something is submitted via complete() method and return the submitted value, or it will throw the exception supplied via completeExceptionally() wrapped in an ExecutionException.
There is also get() version with timeout limit:
String result = future.get(60, TimeUnit.SECONDS);
Finally got it to work using Executor Framework.
final int[] value = new int[1];
pollExecutor.scheduleWithFixedDelay(new Runnable() {
Map<String, String> statMap = null;
#Override
public void run() {
try {
statMap = coldService.doPoll(id);
} catch (Exception e) {
}
if (statMap != null) {
for (Map.Entry<String, String> entry : statMap
.entrySet()) {
if ("failed".equals(entry.getValue())) {
value[0] = 2;
pollExecutor.shutdown();
}
}
}
}
}, 0, 5, TimeUnit.MINUTES);
try {
pollExecutor.awaitTermination(40, TimeUnit.MINUTES);
} catch (InterruptedException e) {
}

Asynchronously running a task and returning after thread is active

I have been working with threads to send a GET request to a link (all good). However, I need it to run asynchronously, so I made a new thread and ran it. Problem is I need it to return the value returnVar[0] after the thread is done executing. I have tried while loops with !thread.isActive but of course, the method body needs a return statement. I have tried CountdownLatches which you are about to see, but they pause the main thread which I DON'T want. Any ideas are greatly appreciated.
Code:
public String getUUID(String username) {
final String[] returnVar = {"ERROR"};
final CountDownLatch latch = new CountDownLatch(1);
Thread thread = new Thread(() -> {
final String[] response = {"ERROR"};
final JSONObject[] obj = new JSONObject[1];
response[0] = ConnectionsManager.sendGet("https://api.mojang.com/users/profiles/minecraft/" + username);
try {
obj[0] = (JSONObject) new JSONParser().parse(response[0]);
returnVar[0] = (String) obj[0].get("id");
} catch (ParseException e) {
e.printStackTrace();
}
latch.countDown();
});
thread.start();
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
return returnVar[0];
}
I think you should consider using a Callable instead of a Runnable. See this thread for explanation and examples.
Also, it's a little strange that you are using the CountDownLatch with one thread. The latch is useful to make sure multiple threads are started as uniformly as possible rather than some threads getting a 'head start' in a more traditional startup.
this is an improper use of Threads.
your code runs exactly like the below code :
public String getUUID(String username) {
String response = ConnectionsManager.sendGet("https://api.mojang.com/users/profiles/minecraft/" + username);
try {
return (String) ((JSONObject) new JSONParser().parse(response)).get("id");
} catch (ParseException e) {
return "ERROR";
}
}
there are several options to make async call.
one option is to use CompletableFuture :
CompletableFuture.supplyAsync(getUUID("username")).thenAccept(new Consumer<String>() {
#Override
public void accept(String response) {
// response of async HTTP GET
}
});
learn more :
http://www.javaworld.com/article/2078809/java-concurrency/java-concurrency-java-101-the-next-generation-java-concurrency-without-the-pain-part-1.html
http://javarevisited.blogspot.nl/2015/01/how-to-use-future-and-futuretask-in-Java.html
Difference between Future and Promise
https://www.javacodegeeks.com/2011/09/java-concurrency-tutorial-callable.html
http://winterbe.com/posts/2015/04/07/java8-concurrency-tutorial-thread-executor-examples/
http://www.infoq.com/articles/Functional-Style-Callbacks-Using-CompletableFuture

Java/ test & operation after timeout

I hava a test, with:
#test(timeout = 50000)
I want to do some operations if the test fails because the timeout, and only then.
I try the next:
#Test(timeout=60000)
public void test1() {
try{
// code
}
catch(Exception e){
//operations after time out
}
}
But it doesn't work. Any help?
It's not possible to do what you described here with JUnit's timeout parameter because it doesn't provide a callback to handle the operations after it has timed out.
But, you can certainly write your own test harness to do just that. In the below example, I want the code to execute within one second but my actual code execution takes 2 seconds. In this case, we catch the TimeoutException and you can perform your additional operation within that catch block.
#Test
public void testMe() {
// test must finish within one second
int expectedExecutionInSeconds = 1;
RunnableFuture<String> runnableFuture = new FutureTask<String>(new Callable<String>() {
public String call() throws Exception {
// your actual code goes in here
Thread.sleep(2000);
return "ok";
}
});
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(runnableFuture);
try {
String result = runnableFuture.get(expectedExecutionInSeconds, TimeUnit.SECONDS);
assertEquals("ok", result);
}
catch (TimeoutException ex) {
// stop code
runnableFuture.cancel(true);
System.out.println("do other stuff");
}
catch (Exception e) {
fail("other stuff is failing");
}
executorService.shutdown();
}

Categories