簡體   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