0Pricing
Java Academy · レッスン

Future とエラー処理

タイムアウト付きで Future.get を使い、ExecutionException を処理し、実行中のタスクをキャンセルします。

「Future とエラー処理」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。

Futureとは

Future<V>は、非同期計算の完了待ちの結果を表します。完了状態の確認、結果の待機、エラー処理のためのメソッドを提供します。

import java.util.concurrent.*;

ExecutorService pool = Executors.newFixedThreadPool(2);
Future<Integer> future = pool.submit(() -> {
    Thread.sleep(1000);
    return 42;
});

System.out.println("Is done? " + future.isDone()); // false
Integer result = future.get(); // blocks
System.out.println("Result: " + result); // 42
pool.shutdown();

タイムアウト付きfuture.get()

無期限に停止することを防ぐため、必ずタイムアウトを指定する形式を使用してください。

try {
    Integer result = future.get(5, TimeUnit.SECONDS);
    System.out.println(result);
} catch (TimeoutException e) {
    System.out.println("Timed out");
    future.cancel(true); // interrupt the task
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
} catch (ExecutionException e) {
    System.out.println("Task threw: " + e.getCause());
}

ExecutionException

タスクが例外をスローした場合、future.get()はその例外をExecutionExceptionでラップします。getCause()で元の例外を取り出します。

Future<String> failing = pool.submit(() -> {
    throw new IllegalArgumentException("bad input");
});

try {
    failing.get();
} catch (ExecutionException e) {
    Throwable cause = e.getCause();
    System.out.println(cause.getClass().getSimpleName()); // IllegalArgumentException
    System.out.println(cause.getMessage()); // bad input
}

Futureのキャンセル

cancel(mayInterruptIfRunning)はタスクのキャンセルを試みます。成功するとtrueを返します。mayInterruptIfRunningがtrueの場合、実行中のスレッドに割り込みが送信されます。

Future<String> f = pool.submit(() -> {
    try {
        Thread.sleep(10_000); // long task
        return "done";
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        return "interrupted";
    }
});

boolean cancelled = f.cancel(true); // send interrupt
System.out.println("Cancelled: " + cancelled); // true
System.out.println("Is cancelled: " + f.isCancelled()); // true

isCancelledとisDoneの違い

isDone()は、タスクが正常に完了した場合、例外をスローした場合、またはキャンセルされた場合にtrueを返します。isCancelled()は、キャンセルされた場合にのみtrueを返します。

// After cancel:
System.out.println(f.isDone());       // true
System.out.println(f.isCancelled()); // true

// After normal completion:
Future<Integer> done = pool.submit(() -> 5);
done.get(); // wait
System.out.println(done.isDone());       // true
System.out.println(done.isCancelled()); // false

利用可能になった結果を取得するCompletionService

ExecutorCompletionServiceはプールをラップし、次に完了したFutureを取得するtake()メソッドを提供します。取得順序は送信順序ではなく、完了順序です。

ExecutorCompletionService<Integer> cs =
    new ExecutorCompletionService<>(pool);

for (int i = 0; i < 5; i++) {
    final int delay = 5 - i; // submit fastest last
    cs.submit(() -> { Thread.sleep(delay * 100); return delay; });
}

for (int i = 0; i < 5; i++) {
    Future<Integer> f = cs.take(); // next completed
    System.out.println(f.get());
}

複数のFutureを安全に処理する

多数のFutureから結果を収集する場合は、各Futureを個別に反復処理し、例外も個別に処理します。

List<Future<String>> futures = new ArrayList<>();
for (int i = 0; i < 5; i++) {
    final int id = i;
    futures.add(pool.submit(() ->
        id % 2 == 0 ? "ok_" + id : (() -> { throw new RuntimeException("fail_"+id); }).get()
    ));
}

for (Future<String> f : futures) {
    try {
        System.out.println(f.get());
    } catch (ExecutionException e) {
        System.out.println("Error: " + e.getCause().getMessage());
    }
}

プールのシャットダウン後のFuture.get()

shutdown()の後にタスクを送信すると、RejectedExecutionExceptionがスローされます。ただし、シャットダウン前に送信したFutureは、シャットダウン後も取得できます。

ExecutorService pool2 = Executors.newFixedThreadPool(2);
Future<Integer> f = pool2.submit(() -> 99);
pool2.shutdown(); // no new tasks

// Still valid — task was submitted before shutdown:
System.out.println(f.get()); // 99

try {
    pool2.submit(() -> 0); // throws!
} catch (RejectedExecutionException e) {
    System.out.println("Pool shut down");
}

FutureTask:手動Future

FutureTask<V>はRunnableとFuture<V>の両方を実装します。ExecutorServiceを使わずにFutureが必要な場合に便利です。

FutureTask<String> task = new FutureTask<>(() -> "computed");
new Thread(task).start(); // run in any thread
System.out.println(task.get()); // computed

Futureによるリトライパターン

future.get()の周囲に簡単なリトライ処理を実装します。

Future<String> future = pool.submit(() -> {
    if (Math.random() < 0.7) throw new RuntimeException("transient error");
    return "success";
});

for (int attempt = 0; attempt < 3; attempt++) {
    try {
        System.out.println(future.get());
        break;
    } catch (ExecutionException e) {
        System.out.println("Attempt " + (attempt+1) + " failed");
        if (attempt == 2) throw e;
        future = pool.submit(() -> "retry"); // resubmit
    }
}

Futureの制限

java.util.concurrent.Futureには次の制限があります。

  • コールバックがなく、get()でブロックする必要があります
  • 変換処理をチェーンできません
  • 複数のFutureを組み合わせられません

リアクティブでノンブロッキングな合成には、CompletableFuture(次のコース)を使用します。

確認問題

タスクが例外をスローしました。future.get()を呼び出すと、どの例外がスローされますか?

復習:Futureとエラー処理

重要なポイント:

  • future.get()はブロックするため、必ずタイムアウトを指定する形式を使用します
  • ExecutionExceptionはタスクの例外をラップします。getCause()で元の例外を取り出します
  • cancel(true)は割り込みを送信します。isDoneとisCancelledで状態を確認します
  • ExecutorCompletionService.take()は完了順にFutureを取得します
  • FutureTaskはRunnableとFutureの両方を実装します

よくある質問

「Future とエラー処理」レッスンは無料ですか?

はい。「Future とエラー処理」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。

「Future とエラー処理」で何を学びますか?

タイムアウト付きで Future.get を使い、ExecutionException を処理し、実行中のタスクをキャンセルします。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Java Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「Future とエラー処理」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJava Academyレッスンでコードを書いて実行できますか?

はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. ExecutorService とスレッドプールの種類
  2. タスクの送信:Runnable と Callable
  3. Future とエラー処理
  4. 定期タスクのための ScheduledExecutorService
← Java Academyに戻る