springboot~CompletableFuture平行計算

张占岭發表於2024-05-06

在Spring中,CompletableFuture通常用於非同步程式設計,可以方便地處理非同步任務的執行和結果處理,CompletableFuture 是 Java 8 引入的一個類,用於支援非同步程式設計和併發操作。它基於 Future 和 CompletionStage 介面,提供了豐富的方法來處理非同步任務的執行和結果處理。

下面是 CompletableFuture 實現的一些關鍵原理:

  1. 執行緒池支援CompletableFuture 內部使用執行緒池來執行非同步任務,可以透過指定不同的執行緒池來控制任務的執行方式。預設情況下,CompletableFuture 使用 ForkJoinPool.commonPool() 作為預設的執行緒池。

  2. 回撥函式CompletableFuture 支援鏈式呼叫,可以透過 thenApply(), thenAccept(), thenRun(), thenCompose() 等方法新增回撥函式,在非同步任務完成後處理任務的結果或執行下一步操作。

  3. 異常處理CompletableFuture 提供了 exceptionally(), handle(), whenComplete() 等方法來處理非同步任務中可能丟擲的異常,確保異常能夠被捕獲並處理。

  4. 組合操作CompletableFuture 支援多個 CompletableFuture 物件之間的組合操作,如 thenCombine(), thenCompose(), allOf(), anyOf() 等方法,實現並行執行、序列執行、等待所有任務完成等功能。

  5. CompletableFuture 工廠方法:除了 supplyAsync() 方法外,CompletableFuture 還提供了一系列工廠方法來建立 CompletableFuture 物件,如 runAsync(), completedFuture(), failedFuture() 等,方便快速建立並管理非同步任務。

總的來說,CompletableFuture 的實現基於 Future 和 CompletionStage 介面,利用執行緒池、回撥函式、異常處理、組合操作等機制,提供了強大而靈活的非同步程式設計功能,使得開發人員能夠更加方便地處理非同步任務的執行和結果處理。

使用方法(一)鏈式

如果我們的業務方法已經寫完了,這時可以直接透過supplyAsync方法來呼叫這些已知的方法,而不需要重新開發

CompletableFuture<String> a1 = CompletableFuture.supplyAsync(() -> {
      try {
          Thread.sleep(1000);
      } catch (InterruptedException e) {
          throw new RuntimeException(e);
      }
      return "Hello World";
  });
  CompletableFuture<String> a2 = CompletableFuture.supplyAsync(() -> {
      try {
          Thread.sleep(2000);
      } catch (InterruptedException e) {
          throw new RuntimeException(e);
      }
      return "Hello World";
  });
  CompletableFuture<String> a3 = CompletableFuture.supplyAsync(() -> {
      try {
          Thread.sleep(3000);
      } catch (InterruptedException e) {
          throw new RuntimeException(e);
      }
      return "Hello World";
  });

  // 這塊最後是平行計算時間為3秒
  CompletableFuture.allOf(a1, a2, a3).join();

  String result = a1.get() + " | " + a2.get() + " | " + a3.get();

使用方法(二)獨立方法

如果方法比較獨立,並且之前沒有開發過,那麼你可以透過非同步方法來將這些邏輯與呼叫程式碼解耦

@Service
@EnableAsync
public class ParallelTaskService {

    @Async
    public CompletableFuture<String> task1() {
        // 模擬一個耗時操作
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return CompletableFuture.completedFuture("Task 1 completed");
    }

    @Async
    public CompletableFuture<String> task2() {
        // 模擬另一個耗時操作
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return CompletableFuture.completedFuture("Task 2 completed");
    }
}

// 平行計算時,響應時間是2和3秒之中最大值,即3秒
@GetMapping("/hello-world2")
public CompletableFuture<String> helloWorld2() {
    CompletableFuture<String> task1Result = parallelTaskService.task1();
    CompletableFuture<String> task2Result = parallelTaskService.task2();

    // 等待所有任務都完成
    CompletableFuture<Void> allOf = CompletableFuture.allOf(task1Result, task2Result);

    // 處理所有任務完成後的邏輯
    return allOf.thenApply(voidResult -> {
        String result = task1Result.join() + " | " + task2Result.join();
        return result;
    });
}

相關文章