executorThreadPool检查任务完成或超时到期

时间:2016-07-01 04:15:36

标签: java multithreading concurrency executorservice

我正在使用executorservice,每个webservice调用产生大约9-10个Callable任务并提交到executorService线程池。对于线程池大小为100的应用程序,有1个单独的executorService。 当我提交callables时,我有一个2 For循环。外部循环运行直到指定的超时到期或完成的hashset size ==提交的任务大小;内部循环遍历Callables,如果isDone()== true,那么这些内容将被收集在“已完成”中。 HashSet的。当外环条件失败时,我遍历“已完成”哈希集中的可调用对象并聚合结果。 问题是我确信有比使用2个循环更优雅的解决方案。

如果所有任务完成或超时到期,我可以收到通知的最佳方式是什么?任何框架,库等或设计模式?

2 个答案:

答案 0 :(得分:1)

您基本上有两个选项,推送

是你已经尝试过的 - 发送所有异步任务,保留对它们的引用并调用isDone()直到它们全部完成。

另一方面,

推送会分离调用和通知任务。您将调用异步任务,然后该方法将立即返回。通知将由任务本身处理,他们需要在工作完成时通知。

如果您正在使用Java EE,则Observer PatternCDI 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;
}