我试图实现的一个想法如下。
- 我有1000个url可以下载数据,用于后期处理(比如计算一些统计数据)。我真的不需要所有的下载都能成功完成,但要尽可能多
- 我假设有些位置可能不可用,要么没有任何有价值的响应(例如,HTTP 503),要么处理请求需要超过TO=10秒的时间
- 我有T=5个线程并行处理url,每个线程都有相等的超时to
- 一旦完成(我预计会发生的事情比to早得多),我就会汇总一些统计数据(这是一个非常快速的操作),并开始下一次下载(如果有的话)
到目前为止,我提出的解决方案是
ExecutorService executorService = Executors.newFixedThreadPool(T);
ExecutorCompletionService<MyResult> completionService = new ExecutorCompletionService<>(executorService);
urls.forEach(url -> {
Callable<MyResult> callable = () -> new MyResult(url);
completionService.submit(callable);
});
for (int i = 0; i < urls.size(); i++) {
Future<MyResult> resultFuture = completionService.poll(TO, TimeUnit.SECONDS);
if (resultFuture == null)
continue;
MyResult myResult = resultFuture.get();
myAggregate(myResult.getRate());
}
这看起来有点像我正在努力实现的目标。但例如,它既没有给每次下载提供相同的超时时间,也没有正确地取消Futures。那么,正确的解决方案是什么?
尝试使用invokeAll方法,只需将Callables放入List中,然后在ExecutorService上调用invokeAll(),将其作为第二个和第三个参数超时。
executorService.invokeAll(callableList, 20, TimeUnit.SECONDS);