Reputation: 265
I have 3 FutureTask<T>
Objects. I want that they are processed asynchronously. However, as soon as one of the FutureTasks' get()
methods doesn't return null
I want to continue i.e my method (wrapper) returns and doesn't wait until the other two FutureTasks are processed.
I thought about something like:
private File wrapper(final File file) {
ExecutorService executors = Executors.newCachedThreadPool();
File returnFile;
FutureTask<File> normal= ...
FutureTask<File> medium=...
FutureTask<File> huge=...
executors.execute(normal);
executors.execute(medium);
executors.execute(huge);
try {
if((returnFile=normal.get()) != null ||
(returnFile=medium.get()) != null ||
(returnFile=huge.get()) != null)
return returnFile;
} catch(ExecutionException | InterruptedException e) { }
}
I'm not sure how to capture the exceptions (thrown by the get()) in a proper way because I assume they will be thrown since I just return without waiting for the other two tasks to be completed. Moreover I've doubts that the code will work like intended. I feel that I'm close to the solution but missing something.
Upvotes: 6
Views: 742
Reputation: 11107
I had an idea to design it using BlockingQueue. You extend your tasks with done method submitting results into BlockinQueue and, once client received first result, it cancels other tasks. On the other hand, experts suggest using ExecutorCompletionService instead. It seems to serialize results imself and has all appropriate examples.
Upvotes: 0
Reputation: 31
May I suggest to check for FutureTask::isDone?
Would be something like this then:
while(true) {
if (normal.isDone()) {
return normal.get();
}
if (medium.isDone()) {
return medium.get();
}
if (huge.isDone()) {
return huge.get();
}
}
EDIT: You could cancel the other tasks as soon as you have one result at hand.
Using FutureTask::get is not what you look for as it would most likely always return the result of normal.get() because the documentation already states that:
Waits if necessary for the computation to complete, and then retrieves its result.
To clarify the above: If you use FutureTask::get the first FutureTask you call get on will most likely block and wait until a result is available to return.
EDIT2:
Wrap that loop into a new Runnable, executed by the ExecutorService, passing the first result available to another method or implement a Callback and there's no more busy waiting.
Upvotes: 1