如何等待超时的ListenableFuture列表

Dan*_*iel 5 java future guava

我正在解决一个我有问题的问题List<ListenableFuture<T>>。我想将所有这些期货的结果汇总为List<T>一个超时。天真的方法是这样的:

List<T> blockForResponses(List<ListenableFuture<T>> futures, long timeoutMillis) {
    return futures.stream()
        .map(future -> future.get(timeoutMillis,TimeUnit.MILLISECONDS)
        .collect(Collectors.toList());
}
Run Code Online (Sandbox Code Playgroud)

这是行不通的,因为它等待每个将来的超时,我希望它是整个列表的超时。手动跟踪经过了多少时间也是行不通的,因为如果第一个超时,就没有时间尝试其他时间了。

我正在寻找的解决方案将对所有期货强制执行超时,并在超时时间过去或列表中的所有期货均已完成时返回。然后,我可以自己检查列表中的每个将来,以汇总结果并检查哪些超时。

Dan*_*iel 6

事实证明,这个问题比我想象的要简单。我能够使用该Futures.allAsList方法,然后捕获TimeoutException

List<T> blockForResponses(List<ListenableFuture<T>> futures, long timeoutMillis) {
    ListenableFuture<List<T>> futureOfList = Futures.allAsList(futures);
    List<T> responses;
    try {
        responses = futureOfList.get(timeoutMillis, TimeUnit.MILLISECONDS);
    } catch (TimeoutException e) {
        responses = new ArrayList<>();
        for (ListenableFuture<T> future : futures) {
            if (future.isDone()) {
                responses.add(Uninterruptibles.getUninterruptibly(future));
            }
        }
    }
    return responses;
}
Run Code Online (Sandbox Code Playgroud)


小智 0

所以我摆弄了一下(直到今天晚上才使用 Guava 的 Listenable 接口),但我认为这可能对你有用:package basic;

import static com.google.common.util.concurrent.Futures.catching;
import static com.google.common.util.concurrent.Futures.successfulAsList;
import static com.google.common.util.concurrent.Futures.withTimeout;

import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningScheduledExecutorService;
import com.google.common.util.concurrent.MoreExecutors;

public class FuturesExample {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ListeningScheduledExecutorService scheduledExecutorService = MoreExecutors
                .listeningDecorator(Executors.newScheduledThreadPool(20));
        List<ListenableFuture<Integer>> list = new LinkedList<>();
        for (int i = 1; i <= 4; i++) {
            list.add(catching(
                    withTimeout(scheduledExecutorService.submit(getCallback(i * 1000, i)), 3, TimeUnit.SECONDS,
                            scheduledExecutorService),
                    TimeoutException.class, exception -> 0, scheduledExecutorService));
        }
        ListenableFuture<List<Integer>> result = successfulAsList(list);
        Optional<Integer> sum = result.get().stream().reduce(Integer::sum);
        System.out.println(sum.orElse(-1));
        scheduledExecutorService.shutdownNow();
    }

    private static Callable<Integer> getCallback(int timeout, int value) {
        return () -> {
            Thread.sleep(timeout);
            return value;
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:使用 Futures 的静态导入时,代码会更干净一些