我正在使用executorservice,每个webservice调用产生大约9-10个Callable任务并提交到executorService线程池。对于线程池大小为100的应用程序,有1个单独的executorService。 当我提交callables时,我有一个2 For循环。外部循环运行直到指定的超时到期或完成的hashset size ==提交的任务大小;内部循环遍历Callables,如果isDone()== true,那么这些内容将被收集在“已完成”中。 HashSet的。当外环条件失败时,我遍历“已完成”哈希集中的可调用对象并聚合结果。 问题是我确信有比使用2个循环更优雅的解决方案。
如果所有任务完成或超时到期,我可以收到通知的最佳方式是什么?任何框架,库等或设计模式?
答案 0 :(得分:1)
您基本上有两个选项,拉或推送。
拉是你已经尝试过的 - 发送所有异步任务,保留对它们的引用并调用isDone()直到它们全部完成。
另一方面,推送会分离调用和通知任务。您将调用异步任务,然后该方法将立即返回。通知将由任务本身处理,他们需要在工作完成时通知。
如果您正在使用Java EE,则Observer Pattern或CDI Events可以轻松实现此通知。
我个人更喜欢push方法,因为它清理代码并分离调用任务和处理结果的顾虑。无论哪种方式都很好。
答案 1 :(得分:1)
您可以使用CompletableFuture
。
CompletableFuture.supplyAsync()
中的任务是否会在HashSet
。CompletableFuture
thenCombine()
中汇总所有这些内容
get()
超时,如果发生TimeoutException
,则使用默认值完成所有计算期货。然后聚合将立即返回部分结果。这也是一种推送式方法,但所有通知逻辑都由CompletableFuture
类完成。
示例(使用整数和作为聚合)
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
Set<CompletableFuture<Integer>> calculations = new HashSet<>();
CompletableFuture<Integer> sum = CompletableFuture.completedFuture(0);
for (int i = 0; i < 100; i++) {
// submit to thread pool
CompletableFuture<Integer> calculation =
CompletableFuture.supplyAsync(CompleteableFutureGather::longCalculation, executorService);
calculations.add(calculation);
sum = sum.thenCombine(calculation, Integer::sum); // set up future aggregation
}
int total = 0;
try {
total = sum.get(5, TimeUnit.SECONDS); // set timeout
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
throw (RuntimeException) e.getCause();
} catch (TimeoutException e) {
// preemptively complete calculations with default value, those already completed will be unaffected
calculations.forEach(integerCompletableFuture -> integerCompletableFuture.complete(0));
total = sum.getNow(0); // everything is complete so partial aggregation will be returned immediately
}
System.out.println(total);
}
private static Integer longCalculation() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return 1;
}