繁体   English   中英

主线程不等待 CompletableFuture.runAsync() 并返回响应

[英]main thread does not wait for CompletableFuture.runAsync() and returned the response

I have a function which has a invoke method, which internally calls an soap API, and it's taking like 22 seconds to execute, there are few other methods also in code, So totally deleteSoemthing()(code below) method takes like 24 seconds,

现在,我尝试在单独的线程中运行耗时方法,所以我的假设是即使它是单独的线程,它也只会优化到 2 秒,因为它从总共 24 秒中花费了 22 秒。

所以它可能需要 22 秒而不是 24 秒,因为它是并行运行的。

但是当我通过 postman 运行它时,执行只需要 2 秒,我的意思是在 2 秒内返回响应。 并且单独的线程继续运行(当我通过调试检查时)。

所以,我的疑问是,主线程是否不等待此任务完成并发送回响应。 或者它只是发送响应并继续在后台运行异步任务

void deleteSomething(){

CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
                try {
                    invoke("invoking a soap API"));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });

//some other code

}

如果您希望主线程(请求)并行处理“一些其他代码”和“调用 SOAP API”,然后组合并将响应返回给最终用户,那么这将不起作用。

当我们创建一个 CompletableFuture 实例时,它会在另一个线程中分离计算并立即返回 Future。 如果你需要阻塞结果,那么你需要调用它的get方法。 然而,这个过程仍然需要 22+2 = 24 秒才能返回响应。

要并行运行这两个任务,您应该创建两个Callable (s) 并将它们提交给ExecutorService

例如。

  public void deleteSomething(){
    ExecutorService executorService = Executors.newFixedThreadPool(2);
    Collection<Callable<Void>> callables = new ArrayList<>();
    callables.add(() -> doSomeOtherTask());
    callables.add(() -> invokeSoapApi());
    try {
      List<Future<Void>> taskFutureList = executorService.invokeAll(callables);
      taskFutureList.get(0).get();
      taskFutureList.get(1).get();
    } catch (InterruptedException | ExecutionException e) {
      //error
    }
  }

  public Void doSomeOtherTask() {
    //some other code
    return null;
  }

  public Void invokeSoapApi() {
    //soap api call
    return null;
  }

请注意,线程池应在应用程序启动时创建。 因此,如果您真的希望使用它,那么您应该将“executorService”定义为实例变量。 例如。

@Service
public class MyService {

  ...
  ...
  private ExecutorService executorService = Executors.newFixedThreadPool(2);
  ...
  ...
  //your methods
}

这是CompletableFuture的预期行为,如果您检查了它说的文档 -

/**
 * Returns a new CompletableFuture that is asynchronously completed
 * by a task running in the ForkJoinPool#commonPool() after
 * it runs the given action.
 *
 * @param runnable the action to run before completing the
 * returned CompletableFuture
 * @return the new CompletableFuture
 */

你可以使用阻塞 Future.get() 来实现你想要的(如下图)

void deleteSomething(){
    ExecutorService executorService = Executors.newCachedThreadPool();

    Future<Void> future = executorService.submit(() -> {
        invoke("Invoking soap API");
        return null;
    });
    
    //some other code

    future.get();
}

不建议在方法中创建线程池,因为存在与线程创建相关的开销。 理想情况下,线程池应该在应用程序启动时创建。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM