6

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.

Ian2thedv
  • 2,691
  • 2
  • 26
  • 47
Brenne
  • 265
  • 1
  • 3
  • 11
  • thingy here is that you could have result immediately available for Task huge, but you are needlessly blocked waiting for long running Task normal. If i understand your requirement correctly, it is sufficient that only one of these completes for processing. – John Jul 20 '15 at 13:00
  • I see that `FutureTask` exposes done() for you to override when one is ready. You cancel the others (the whole competing list of tasks). Basically, you create one more task to wait for that signal from done(). – Val Jul 20 '15 at 13:01
  • FRP should provide futures like `val p = Promise[Image] ; Future {p.tryComplete(img2)} ; Future {p.tryComplete(img1)} ; p.future` Here p.future will wait for the image1 or 2 whichever is completed first. Another will fail at tryComplete and error will not propagate anywhere because it is designed for this purpose, to complete only the first result. Probably you have something like that in Java 8. – Val Jul 20 '15 at 13:28

2 Answers2

1

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.

Oliver
  • 31
  • 1
  • 6
  • Busy wait? What a parallel processing masterpiece! – Val Jul 20 '15 at 13:13
  • 1
    It was not my intent to promote busy wait. I just tried to show the problem with FutureTask::get. :) Still, thank you for pointing that out! – Oliver Jul 20 '15 at 13:17
  • Please add a link to cancel method documentation http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/FutureTask.html#cancel%28boolean%29 – Danil Gaponov Jul 20 '15 at 13:33
  • How executing busy wait in the ExecutorService tears down the busy waiting? – Val Jul 21 '15 at 06:34
  • 1
    No busy waiting with a callback. Either by using https://code.google.com/p/guava-libraries/wiki/ListenableFutureExplained or implementing it yourself. Maybe it is because I'm no native English speaker but I thought my sentence made sense from my German perspective. – Oliver Jul 21 '15 at 07:41
0

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.

Community
  • 1
  • 1
Val
  • 1
  • 8
  • 40
  • 64