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

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

我有一个函数,它有一个 invoke 方法,它在内部调用一个 soap API, 执行大约需要 22 秒,代码中也几乎没有其他方法, 所以完全 deleteSoemthing()(下面的代码)方法需要 24 秒,

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

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

但是当我 运行 通过邮递员执行此操作时,执行仅需 2 秒,我的意思是响应在 2 秒内返回。并且单独的线程保持 运行ning(当我通过调试检查时)。

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

void deleteSomething(){

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

//some other code

}

如果您希望主线程(请求)并行处理“一些其他代码”和“调用 SOAP API”,然后合并 return 对最终用户的响应,则这行不通。

当我们创建一个 CompletableFuture 实例时,它会在另一个线程中分离计算并立即 returns Future。如果你需要屏蔽结果,那么你需要在它上面调用get方法。但是,此过程仍需要 22+2 = 24 秒才能得到 return 响应。

为了运行这两个并行任务,你应该创建两个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();
}

不建议在方法中创建线程池,因为线程创建会产生开销。理想情况下,应在应用程序启动时创建线程池。