【问题标题】:Java 8 completable future to execute methods parallelJava 8 可完成的未来并行执行方法
【发布时间】:2021-08-03 22:17:41
【问题描述】:

我有 3 种方法需要并行运行,因为它们相互独立,并在最后组合每个方法的结果并将其作为响应发送。我也需要处理异常。

在不同的帖子中,我找到了以下代码并进行了相应的修改。

public Response getResponse() {
    Response resultClass = new Response();
   try {
    CompletableFuture<Optional<ClassA>> classAFuture
        = CompletableFuture.supplyAsync(() -> service.getClassA() );
    CompletableFuture<ClassB> classBFuture
        = CompletableFuture.supplyAsync(() -> {
             try {
                   return service.getClassB(); 
              }
              catch (Exception e) {
                   throw new CompletionException(e);
              }
     });
    CompletableFuture<ClassC> classCFuture
        = CompletableFuture.supplyAsync(() -> { 
            try {
                return service.getClassC();
            } catch (Exception e) {
                throw new CompletionException(e);
            }
    });

   CompletableFuture<Response> responseFuture =
    CompletableFuture.allOf(classAFuture, classBFuture, classCFuture)
         .thenApplyAsync(dummy -> {
            if (classAFuture.join().isPresent() {
               ClassA classA = classAFuture.join();
               classA.setClassB(classBFuture.join());
               classA.setClassC(classCFuture.join());
               response.setClassA(classA)
             }
            return response;
         });
   responseFuture.join();
  } catch (CompletionExecution e) {
    throw e;
  }
  return response;
}

以上是否应该正确并行运行?我知道这需要更多时间,我想确保我做得对。

【问题讨论】:

    标签: java java-8 completable-future


    【解决方案1】:

    这个想法是正确的,但这一切都可以用少得多的代码来完成:

      public Response getResponse() {
        CompletableFuture<Optional<ClassA>> classAFuture = CompletableFuture.supplyAsync(() -> service.getClassA());
        CompletableFuture<ClassB> classBFuture = CompletableFuture.supplyAsync(() -> service.getClassB());
        CompletableFuture<ClassC> classCFuture = CompletableFuture.supplyAsync(() -> service.getClassC());
        
        try {
          return CompletableFuture.allOf(classAFuture, classBFuture, classCFuture)
            .thenApply(() -> {
              Response response = new Response();
              Optional<ClassA> maybeA = classAFuture.get();
              if (maybeA.isPresent()) {
                ClassA classA = maybeA.get();
                classA.setClassB(classBFuture.get());
                classA.setClassC(classCFuture.get());
                response.setClassA(classA);
              }
              return response;
            }).get();
        } catch (ExecutionException e) { // Ususally the exception is wrapped to ExecutionException by java concurrency framework itself
            Throwable cause = e.getCause();
            if (cause != null) {
              throw cause;
            } else {
              throw e;
            }
        }
      }
    

    主要内容:

    1. 您无需将异常包装到CompletionException
    2. 您不需要使用thenApplyAsync。只是thenApply 是一回事,除非您想非常具体地确定要使用的线程类型。检查此以获取更多信息https://stackoverflow.com/a/47489654/3020903
    3. 你不需要join() 任何东西。当CompletableFuture.all 完成时,您可以确定所有提供的作业都已完成,然后调用get() 将返回值。

    至于您能否确定作业 A、B 和 C 将并行运行。是和不是。如果有足够的系统资源来并行运行它们,它将并行运行。您已尽力要求它们并行运行。也许在某些时候您还想提供自定义线程池以获得更多控制权,但这是另一天的话题。

    【讨论】:

    • 感谢您的回答@Tarmo。方法 getClassB() 和 getClassC() 抛出错误,所以如果我在 try catch 中不处理它,它会说错误未处理异常。
    【解决方案2】:

    如果你想并行运行方法,你应该使用 ExecutorService。试试这样的:

    ExecutorService myExecutor = Executors.newFixedThreadPool(3);
            List<Future<Object>> futures = myExecutor.invokeAll(
                Arrays.asList(
                    () -> service.getClassA(),
                    () -> service.getClassB(),
                    () -> service.getClassC(),
                )
            );
            myExecutor.shutdown();
    

    【讨论】:

      猜你喜欢
      • 2015-05-10
      • 1970-01-01
      • 2014-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-27
      相关资源
      最近更新 更多