我正在使用 ExecutorService 来提交一批任务。我这样做是这样的:
ListeningExecutorService exec = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(threads));
List<ListenableFuture<Whatever>> futures = new ArrayList<>();
for (int i = 0; i < 100; i++) {
results.add(exec.submit(new MyTask(i)));
}
ListenableFuture<List<Whatever>> listListenableFuture = Futures.successfulAsList(futures);
try {
List<Whatever> responses = listListenableFuture.get(2000, TimeUnit.MILLISECONDS);
for (Whatever response : responses) {
LOG.info("Yay!");
}
} catch (TimeoutException e) {
LOG.info("Timeout Exception");
} catch (Exception e) {
// Nay!
}
这里的问题是 - 如果其中一个任务花费的时间超过2000毫秒,则抛出TimeoutException
并且我在响应中什么也得不到,尽管某些任务可能已经完成了。
所以我想检索已经完成的任务的响应(部分或完整),直到超时(2000ms)。例如:
(相对于批次调用的START_TIME的时间)
任务-1:1000ms
任务-2: 3000ms
任务-3:1800ms
的输出:
超时例外
期望输出:
耶! &lt; - 对应于任务-1
耶! &lt; - 对应于task-3
我想到的一个解决方案是单独获取期货并将其超时设置为MAX(0, TIME_OUT - TIME_NOW - START_TIME)
。这可能有用,但对我来说似乎不是一个干净的解决方案。
答案 0 :(得分:0)
您可以使用decorate callable来处理超时。
假设这是原始的可调用:
class OriginalCallable implements Callable<String> {
@Override
public String call() throws Exception {
return "";
}
}
你可以用这个原始的callable和执行者构建一个可调用的decolable:
class DecorateCallable implements Callable<String> {
ExecutorService executorService;
OriginalCallable callable;
public DecorateCallable(ExecutorService executorService, OriginalCallable callable) {
this.executorService = executorService;
this.callable = callable;
}
@Override
public String call() throws Exception {
Future<String> future = executorService.submit(callable);
try {
return future.get(2000, TimeUnit.SECONDS);
} catch (TimeoutException | InterruptedException e) {
}
return null;
}
}
如果你决定使用它,你需要加倍池大小:
Executors.newFixedThreadPool(threads * 2);
并在将它们放入最终结果集之前添加一些像if(future.get() != null)
这样的条件。
答案 1 :(得分:0)
如果您使用Futures.getChecked,则会吞下超时异常,并且将来会返回null。查看以下代码,其中一个任务抛出TimeoutException,相应的future将返回null。
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
<script src="https://www.google.com/recaptcha/api.js"></script>
<button id="btn1">Submit</button>