AnOldSoul
AnOldSoul

Reputation: 4207

How to get the execution results of ExecutorService without blocking the current code path?

I have a service which adds a bunch of requests to Callables and then prints the results of the executions. Currently the service request is blocked until I print all the Future results from the execution. However I want to return 200 to the requestor and run these requests in parallel without blocking the request. How can I achieve this? Below is my code.

Below is my code to run parallel code.

public void runParallelFunctions(Callable<Map<String, String>> invokerTask) {
        List<Callable<Map<String, String>>> myTasks = new ArrayList<>();
        for (int i = 0; i < invocationCount; i++) {
            myTasks.add(invokerTask);
        }
        List<Future<Map<String, String>>> results = null;
        try {
            results = executorService.invokeAll(myTasks);
        } catch (InterruptedException e) {
        }
        this.printResultsFromParallelInvocations(results);
    }

Below is how I print the results from the Futures.

private void printResultsFromParallelInvocations(List<Future<Map<String, String>>> results) {
        results.forEach(executionResults -> {
            try {
                executionResults.get().entrySet().forEach(entry -> {
                    LOGGER.info(entry.getKey() + ": " + entry.getValue());
                });
            } catch (InterruptedException e) {
            } catch (ExecutionException e) {
            }
        });
    }

Below is how I'm invoking the above methods when someone places a request to the service.

String documentToBeIndexed = GSON.toJson(indexDocument);
int documentId = indexMyDocument(documentToBeIndexed);
createAdditionalCandidatesForFuture(someInput);
return true;

In the above code, I call the createAdditionalCandidatesForFuture and then return true. But the code still waits for the printResultsFromParallelInvocations method to complete. How can I make the code return after invoking createAdditionalCandidatesForFuture without waiting for the results to print? Do I have to print the results using another executor thread or is there another way? Any help would be much appreciated

Upvotes: 1

Views: 1123

Answers (2)

adarsh
adarsh

Reputation: 1503

The answer is CompletableFuture.

Updated runParallelFunctions:

public void runParallelFunctions(Callable<Map<String, String>> invokerTask) {
    // write a wrapper to handle exception outside CompletableFuture
    Supplier<Map<String, String>> taskSupplier = () -> {
        try {
            // some task that takes a long time
            Thread.sleep(4000);
            return invokerTask.call();
        } catch (Exception e) {
            System.out.println(e);
        }
        // return default value on error
        return new HashMap<>();
    };
    
    for (int i = 0; i < 5; i++) {
        CompletableFuture.supplyAsync(taskSupplier, executorService)
                         .thenAccept(this::printResultsFromParallelInvocations);
    }
    // main thread immediately comes here after running through the loop
    System.out.println("Doing other work....");
}

And, printResultsFromParallelInvocations may look like:

private void printResultsFromParallelInvocations(Map<String, String> result) {
        result.forEach((key, value) -> System.out.println(key + ": " + value));
    }

Output:

Doing other work....
// 4 secs wait
key:value

Upvotes: 2

Eddie Lopez
Eddie Lopez

Reputation: 1139

Calling get on a Future will block the thread until the task is completed, so yes, you will have to move the printing of the results to another thread/Executor service.

Another option is that each task prints its results upon completion, provided they are supplied with the necessary tools to do so (Access to the logger, etc). Or putting it in another way, each task is divided into two consecutive steps: execution and printing.

Upvotes: 0

Related Questions