I have a method which returns a List
of futures
List<Future<O>> futures = getFutures();
Now I want to wait until either all futures are done processing successfully or any of the tasks whose output is returned by a future throws an exception. Even if one task throws an exception, there is no point in waiting for the other futures.
Simple approach would be to
wait() {
For(Future f : futures) {
try {
f.get();
} catch(Exception e) {
//TODO catch specific exception
// this future threw exception , means somone could not do its task
return;
}
}
}
But the problem here is if, for example, the 4th future throws an exception, then I will wait unnecessarily for the first 3 futures to be available.
How to solve this? Will count down latch help in any way? I'm unable to use Future isDone
because the java doc says
boolean isDone()
Returns true if this task completed. Completion may be due to normal termination, an exception, or cancellation -- in all of these cases, this method will return true.
You can use an ExecutorCompletionService. The documentation even has an example for your exact use-case:
The important thing to notice here is that ecs.take() will get the first completed task, not just the first submitted one. Thus you should get them in the order of finishing the execution (or throwing an exception).
Use
CompletableFuture
in Java 8The CompletionService will take your Callables with the .submit() method and you can retrieve the computed futures with the .take() method.
One thing you must not forget is to terminate the ExecutorService by calling the .shutdown() method. Also you can only call this method when you have saved a reference to the executor service so make sure to keep one.
Example code - For a fixed number of work items to be worked on in parallel:
Example code - For a dynamic number of work items to be worked on in parallel:
maybe this would help (nothing would replaced with raw thread, yeah!) I suggest run each
Future
guy with a separated thread (they goes parallel), then when ever one of the got error, it just signal the manager(Handler
class).I have to say the above code would error(didn't check), but I hope I could explain the solution. please have a try.
If you are using Java 8 and don't want to manipulate
CompletableFuture
s, I have written a tool to retrieve results for aList<Future<T>>
using streaming. The key is that you are forbidden tomap(Future::get)
as it throws.This needs an
AggregateException
that works like C#'sThis component acts exactly as C#'s Task.WaitAll. I am working on a variant that does the same as
CompletableFuture.allOf
(equivalento toTask.WhenAll
)The reason why I did this is that I am using Spring's
ListenableFuture
and don't want to port toCompletableFuture
despite it is a more standard wayIf you are using Java 8 then you can do this easier with CompletableFuture and CompletableFuture.allOf, which applies the callback only after all supplied CompletableFutures are done.