Ответ 1
В комментарии Луи, я искал Futures.successfulAsList
Это позволяет мне дождаться завершения всех, а затем проверить, не сработали ли какие-либо фьючерсы.
Guava ПРАВИЛА!
Хорошо, поэтому я знаю, что первый ответ/комментарий здесь будет "использовать один ExecutorService
и использовать invokeAll
". Тем не менее, есть веская причина (с которой я не буду скучать), поскольку мы сохраняем отдельные пулы потоков.
Итак, у меня есть список пулов потоков (ExecutorServices
), и мне нужно сделать другой Callable
в каждом пуле потоков с помощью submit
(там нет проблем). Теперь у меня есть коллекция экземпляров Future
, каждая из которых создана на отдельном ExecutorService
, и я хочу дождаться, когда все они будут завершены ( и сможет предоставить тайм-аут, в который отменены любые неработающие).
Есть ли существующий класс, который сделает это (завершите список экземпляров Future
и разрешите ждать, пока все не будут выполнены)? Если нет, предложения по эффективному механизму будут оценены.
Думал о вызове get
с тайм-аутом для каждого, но ему нужно сделать расчет общего времени, прошедшего для каждого вызова.
Я видел этот пост Подождите, пока не будет выполнено какое-либо будущее, но это расширяет Future
вместо того, чтобы обернуть список из них.
В комментарии Луи, я искал Futures.successfulAsList
Это позволяет мне дождаться завершения всех, а затем проверить, не сработали ли какие-либо фьючерсы.
Guava ПРАВИЛА!
Я не думаю, что JDK предоставляет прямой API, который позволяет вам это делать. Однако, я думаю, что так же просто создать простой метод, который делает это. Вы можете взглянуть на реализацию AbstractExecutorService.invokeAll(), чтобы понять, что это можно сделать.
По сути, вы бы назвали future.get() в каждом будущем, уменьшив время ожидания на время, затрачиваемое на ожидание результата каждый раз, и перед возвратом из метода отмените все выдающиеся фьючерсы.
Возможно, я действительно не понял. Однако для меня это звучит так же просто, как
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;
}
Неужели я ошибаюсь?
Вопрос, который вы связываете, намного сложнее, я думаю, поскольку они только хотят дождаться самого быстрого и, конечно, не имеют представления, что будет самым быстрым.
Это может использовать некоторую очистку, но это должно решить вашу проблему. (Некоторая инкапсуляция опущена для времени и пространства):
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]
}