【Java学習|初心者向け】Javaで複数の非同期処理をスマートに管理する!CompletableFutureのallOfとanyOf活用術

1. 導入:なぜ複数の非同期処理が必要なのか

Javaで非同期処理を行う際、単一のタスクだけでなく「複数のAPIを同時に叩いて、その結果を待つ」といったシーンは非常に多いです。しかし、バラバラに非同期処理を実行すると、結果の待ち合わせや例外処理が複雑になりがちです。今回紹介する CompletableFuture.allOf()anyOf() を使えば、こうした複雑なタスクの同期や管理をシンプルに解決できます。

2. 基礎知識:CompletableFutureとは

CompletableFuture は、Java 8で導入された非同期処理を扱うためのクラスです。単なる「スレッドの実行」にとどまらず、処理が完了した後のアクション(コールバック)や、複数の処理を組み合わせるパイプライン処理を柔軟に行えます。
今回扱うメソッドは、複数のCompletableFutureを1つにまとめるための「結合ツール」だと考えてください。

3. 実装と解決策

allOf() は「指定したすべての処理が完了するまで待機する」メソッドです。例えば、3つの外部サービスからデータを取得し、すべて揃った後に集計処理を行う場合に使用します。
一方、anyOf() は「指定した処理のうち、どれか1つでも完了したら先に進む」メソッドです。複数のサーバーにリクエストを送り、一番早く返ってきた結果を採用する(レースコンディション)ような場面で役立ちます。

4. サンプルプログラム

以下のコードは、allOfを使用した並列タスク実行の例です。そのままコピー&ペーストして実行可能です。

import java.util.concurrent.CompletableFuture;

public class AsyncExample {
    public static void main(String[] args) {
        // 1つ目の非同期タスク
        CompletableFuture<String> task1 = CompletableFuture.supplyAsync(() -> {
            sleep(1000); // 処理をシミュレート
            return "データA";
        });

        // 2つ目の非同期タスク
        CompletableFuture<String> task2 = CompletableFuture.supplyAsync(() -> {
            sleep(2000);
            return "データB";
        });

        // すべてのタスクが完了するまで待機する
        CompletableFuture<Void> allTasks = CompletableFuture.allOf(task1, task2);

        // 完了後に結果を取得して統合する
        allTasks.thenRun(() -> {
            String result1 = task1.join();
            String result2 = task2.join();
            System.out.println("結果: " + result1 + " と " + result2 + " が揃いました");
        }).join(); // メインスレッドが即終了しないように待機
    }

    private static void sleep(int ms) {
        try { Thread.sleep(ms); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
    }
}

5. 応用・注意点:現場で陥りやすい罠

現場で使う際に最も注意すべきは 例外処理 です。allOf() は、いずれか1つの処理が失敗しても、そのままではエラーを無視して進んでしまうことがあります。
また、Java 21以降で注目されている Virtual Threads を併用する場合、スレッド生成のコストは非常に低いため、CompletableFutureを過度に複雑にチェーンさせるよりも、シンプルな構造を心がけるのがベストです。さらに高度な制御が必要な場合は、Java 21の Structured Concurrency(構造化並行処理) の導入も検討してみてください。これらはスレッドの生存期間を明確に管理できるため、より安全で保守性の高いコードが書けます。

コメント

タイトルとURLをコピーしました