当一个未来任务预期结果时继续

时间:2015-07-20 12:46:02

标签: java asynchronous executorservice futuretask

我有3个FutureTask<T>个对象。我希望它们是异步处理的。但是,只要其中一个FutureTasks&#39; get()方法没有返回null我想继续,即我的方法(包装器)返回并且不等到处理其他两个FutureTasks。 我想到了类似的东西:

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) { }
}

我不确定如何以正确的方式捕获异常(由get()抛出),因为我假设它们将被抛出,因为我只是返回而不等待其他两个任务完成。此外,我怀疑代码是否会像预期的那样工作。我觉得我接近解决方案但却遗漏了一些东西。

2 个答案:

答案 0 :(得分:1)

我可以建议检查FutureTask :: isDone吗?

那会是这样的:

while(true) {
    if (normal.isDone()) {
        return normal.get();
    }
    if (medium.isDone()) {
        return medium.get();
    }
    if (huge.isDone()) {
        return huge.get();
    }
}

编辑: 只要手头有一个结果,你就可以cancel完成其他任务。

使用FutureTask::get不是你想要的,因为它很可能总是返回normal.get()的结果,因为文档已经说明:

  

如果需要等待计算完成,然后检索   结果。

澄清以上内容: 如果你使用FutureTask :: get第一个FutureTask,你调用get on很可能会阻塞并等到结果可以返回。

EDIT2:

将该循环包装到一个新的Runnable中,由ExecutorService执行,将第一个结果传递给另一个方法或实现Callback,并且不再忙于等待。

答案 1 :(得分:0)

我有一个想法是使用BlockingQueue进行设计。您可以使用done方法将结果扩展到BlockinQueue,并在客户端收到第一个结果后取消其他任务。另一方面,experts suggest using ExecutorCompletionService代替。它似乎将结果序列化为自己和has all appropriate examples