java 如何等待使用不同的“ExecutorServices”创建的“Future”列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13183692/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 11:48:00  来源:igfitidea点击:

How to wait for list of `Future`s created using different `ExecutorServices`

javaconcurrencyexecutorservicefuture

提问by John B

Ok, so I know the first answer / comment here will be "use one ExecutorServiceand use invokeAll". However, there is a good reason (which I will not bore people with) for us keeping the thread pools separate.

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

So I have a list of thread pools (ExecutorServices) and what I need to do is invoke a different Callableon each thread pool using submit(no problem there). Now I have this collection of Futureinstances, each created on a seperate ExecutorService, and I want to wait for all of them to complete (and be able to provide a timeout at which any not done are cancelled).

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

Is there an existing class that will do this (wrap a list of Futureinstances and allow for a wait till all are done)? If not, suggestions on an efficient mechanism would be appreciated.

是否有一个现有的类可以执行此操作(包装Future实例列表并允许等待所有完成)?如果没有,将不胜感激有关有效机制的建议。

Was thinking of calling getwith a timeout for each but have to do a calculation of the total time passed for each call.

正在考虑get为每个呼叫设置超时,但必须计算每次呼叫通过的总时间。

I saw this post Wait Until Any of Future is Donebut this extends Futureinstead of wrapping a list of them.

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

回答by John B

Per Louis' comment, what I was looking for was Futures.successfulAsList

根据路易斯的评论,我正在寻找的是Futures.successfulAsList

This allows me to wait for all to complete and then check for any futures that failed.

这使我可以等待所有操作完成,然后检查是否有任何失败的期货。

Guava RULES!

番石榴规则!

回答by sjlee

I don't think JDK provides a direct API that lets you do that. However, I think it is equally straightforward to create a simple method that does this. You might want to take a look at the implementation of AbstractExecutorService.invokeAll() to get an idea that this can be done.

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

Essentially, you would call future.get() on each future, decreasing the wait time by the time it took to wait for the result each time, and before returning from the method cancel all outstanding futures.

本质上,您将在每个期货上调用 future.get(),通过每次等待结果所需的时间减少等待时间,并在从该方法返回之前取消所有未完成的期货。

回答by Sir RotN

Maybe I didn't really get it. However, to me it still sounds as simple as

可能我真的没看懂。然而,对我来说,这听起来仍然很简单

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;
}

Am I wrong with that?

我错了吗?

The question you link is much more complex I think, as they only want to wait for the fastest, and of course have no idea which will be the fastest.

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

回答by Cobra1117

This could use some cleanup, but it should solve your problem. (Some encapsulation omitted for time and space):

这可能需要一些清理工作,但它应该可以解决您的问题。(时间和空间省略了一些封装):

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();
        }
    }
}

Then your code would call it like this:

然后你的代码会像这样调用它:

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]
}