当前位置: 首页 > 知识库问答 >
问题:

Java 8可完全并行执行方法

戈念
2023-03-14

我有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;
}

上述各项是否应正确并行运行?我知道这需要更多的时间,我想确保我做对了。

共有2个答案

岳和泽
2023-03-14

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

  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. 您不需要connect()任何东西。当CompletableFuture.all完成时,您可以非常确定所有提供的作业都已完成,然后调用get()将只返回值。

至于你能保证作业A、B和C将并行运行吗。是和否。如果有足够的系统资源并行运行,它将并行运行。你已经尽力要求他们并行运行。也许在某个时候,您还希望提供自定义线程池以获得更多控制,但这是另一天的主题。

屠嘉勋
2023-03-14

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

ExecutorService myExecutor = Executors.newFixedThreadPool(3);
        List<Future<Object>> futures = myExecutor.invokeAll(
            Arrays.asList(
                () -> service.getClassA(),
                () -> service.getClassB(),
                () -> service.getClassC(),
            )
        );
        myExecutor.shutdown();
 类似资料:
  • 我编写了两个功能文件,每个功能文件打开不同的浏览器URL,例如一个是open google。com和secnd一个开放的亚马逊。但事实并非如此。 两个浏览器都打开了谷歌。通用域名格式。此外,它不能与浏览器交互,任何编码到浏览器的操作都不会执行。此外,关闭第一个浏览器会导致第二个浏览器出现空指针异常。 cucumber版本6我从AbstractCucumberTesNG继承开始。然后我创建登录。功能

  • 我试图理解java中完整期货的非阻塞回调性质 有了上面的代码,我总是看到下面看到的输出 线程名称ForkJoinPool.common池工人-1 thenApply Thread name main thenApply Thread name main thenAcceptThread name main Thread name main 这个顺序似乎建议主线程等待所有Futures线程的执行。

  • 我有一个关于Java流和链式可完成期货如何执行的问题。 我的问题是:如果我运行下面的代码,调用,列表中有10个项目需要大约11秒才能完成(列表中的项目数加1)。这是因为我有两个线程并行工作:第一个执行操作,一旦完成,第二个执行操作,第一个开始处理列表中的下一个项目。 如果我注释掉第36行(),那么方法需要大约20秒才能完成。Thread不平行运行;对于列表中的每个项目,操作完成,然后在处理列表中的

  • 在下面的代码中,我试图理解java-8中提供的可选的概念。我创建了下面的例子来掌握orElse()背后的原理。执行代码后,defaultmethod()的主体被执行,并返回 对象y。log语句按照我的预期打印了正确的数据。 问题是,为什么defaultMethod()中的所有日志都没有打印??引入is-orElse()仅返回值,而不执行所提供方法的整个主体。? 代码: 日志:

  • 我有一个viewmodel,它对API执行不同的请求,我现在是这样调用我的API的 这种方法的问题是,我需要等待每一个完成来启动另一个,在我对repo(都是挂起函数)执行此调用后,我通知livedata,但这需要一些时间(4-5秒),并且我希望同时执行所有调用,并在通知我的livedata之前一次捕获它们 我在找像这样的东西 我希望使用Async-Await而不是作业

  • 我用reactiveX Zip做了一些实验,我注意到我在zip中定义的可观察性是一个接一个地执行的。我认为zip的好处是,zip中定义的每一个可观察到的线程都是由一个线程执行的,所以所有这些线程都是并行执行的。有什么方法能达到我想要的吗?。这是我的zip例子