如何等待使用不同的`ExecutorService`创建的`Future`列表

时间:2012-11-01 18:55:57

标签: java concurrency executorservice future

好的,所以我知道这里的第一个答案/评论是“使用一个ExecutorService并使用invokeAll”。但是,有一个很好的理由(我不会让人厌烦)让我们保持线程池分开。

所以我有一个线程池列表(ExecutorServices),我需要做的是使用Callable在每个线程池上调用不同的submit(没问题)。现在我有了Future个实例的集合,每个实例都是在一个单独的ExecutorService上创建的,我想等待所有这些实例完成(并且能够提供超时完成取消)。

是否有现有的类可以执行此操作(包装Future实例列表并允许等待直到完成所有操作)?如果没有,将赞赏有效机制的建议。

考虑为每个调用get调用超时,但必须计算每次调用的总时间。

我看到了这篇文章Wait Until Any of Future is Done,但这扩展了Future而不是包含它们的列表。

4 个答案:

答案 0 :(得分:17)

Per Louis的评论,我所寻找的是Futures.successfulAsList

这允许我等待所有人完成,然后检查任何失败的未来。

番石榴规则!

答案 1 :(得分:2)

我不认为JDK提供了一个直接的API,可以让你这样做。但是,我认为创建一个执行此操作的简单方法同样简单。您可能需要查看AbstractExecutorService.invokeAll()的实现,以了解可以这样做。

基本上,你会在每个未来调用future.get(),每次等待结果所花费的时间减少等待时间,并且在从方法返回之前取消所有未完成的期货。

答案 2 :(得分:1)

也许我没有真正理解它。然而,对我来说,它仍然听起来像

一样简单
public <V> List<V> get(List<Future<V>> futures, long timeout, TimeUnit unit)
          throws InterruptedException, ExecutionException, TimeoutException {
    List<V> result = new ArrayList<V>();
    long end = System.nanoTime() + unit.toNanos(timeout);
    for (Future<V> f: futures) {
        result.add(f.get(end - System.nanoTime(), TimeUnit.NANOSECONDS));
    }
    return result;
}

我错了吗?

我认为你链接的问题要复杂得多,因为他们只想等待最快,当然也不知道哪一个是最快的。

答案 3 :(得分:1)

这可以使用一些清理,但它应该可以解决您的问题。 (对时间和空间省略了一些封装):

public static <T> LatchWithWrappedCallables<T> wrapCallables(Collection<Callable<T>> callablesToWrap)
{
    CountDownLatch latch = new CountDownLatch(callablesToWrap.size());
    List<Callable<T>> wrapped = new ArrayList<Callable<T>>(callablesToWrap.size());
    for (Callable<T> currCallable : callablesToWrap)
    {
        wrapped.add(new CallableCountdownWrapper<T>(currCallable, latch));
    }

    LatchWithWrappedCallables<T> returnVal = new LatchWithWrappedCallables<T>();
    returnVal.latch = latch;
    returnVal.wrappedCallables = wrapped;
    return returnVal;
}

public static class LatchWithWrappedCallables<T>
{
    public CountDownLatch latch;
    public Collection<Callable<T>> wrappedCallables;
}

public static class CallableCountdownWrapper<T> implements Callable<T>
{
    private final Callable<T> wrapped;

    private final CountDownLatch latch;

    public CallableCountdownWrapper(Callable<T> wrapped, CountDownLatch latch)
    {
        this.wrapped = wrapped;
        this.latch = latch;
    }

    @Override
    public T call() throws Exception
    {
        try
        {
            return wrapped.call();
        }
        finally
        {
            latch.countDown();
        }
    }
}

然后你的代码会这样称呼它:

Collection<Callable<String>> callablesToWrap = [Your callables that you need to wait for here];
LatchWithWrappedCallables<String> latchAndCallables = wrapCallables(callablesToWrap);

[Submit the wrapped callables to the executors here]

if(latchAndCallables.latch.await(timeToWaitInSec, TimeUnit.SECONDS))
{
    [Handling for timeout here]
}