広告

Java : Future - API使用例

Future (Java SE 19 & JDK 19) の使用例まとめです。
だいたいのメソッドを網羅済みです。
API仕様のおともにどうぞ。


概要

Futureは、非同期計算の結果を表します。 計算が完了したかどうかのチェック、完了までの待機、計算結果の取得などを行うためのメソッドが用意されています。

クラス構成

Futureはインタフェースは、非同期処理の結果を表します。

  • 処理が完了したかどうかのチェック
  • 完了までの待機
  • 結果の取得

などを行うためのメソッドが用意されています。

主に ExecutorServicesubmit メソッドの戻り値として取得して使います。

// 基準となる時刻
final long current = System.nanoTime();

// 基準となる時刻からの差分を秒として取得
final DoubleSupplier elapsedTime = () -> (System.nanoTime() - current) / 1000000000.0;

try (final var executorService = Executors.newSingleThreadExecutor()) {
    final var future = executorService.submit(() -> {
        try {
            System.out.printf("task : start (%f sec.)%n", elapsedTime.getAsDouble());
            TimeUnit.SECONDS.sleep(2);

            return "abcd";
        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
            return null;
        } finally {
            System.out.printf("task : end (%f sec.)%n", elapsedTime.getAsDouble());
        }
    });

    TimeUnit.SECONDS.sleep(1);

    System.out.printf("future.get ... (%f sec.)%n", elapsedTime.getAsDouble());
    final var ret = future.get();

    System.out.printf("future.get OK! (%f sec.)%n", elapsedTime.getAsDouble());
    System.out.println("ret = " + ret);
}

// 結果
// ↓
//task : start (0.002537 sec.)
//future.get ... (1.003706 sec.)
//task : end (2.004116 sec.)
//future.get OK! (2.004768 sec.)
//ret = abcd

メソッド

boolean cancel (boolean mayInterruptIfRunning)

このタスクの実行の取消しを試みます。

// 基準となる時刻
final long current = System.nanoTime();

// 基準となる時刻からの差分を秒として取得
final DoubleSupplier elapsedTime = () -> (System.nanoTime() - current) / 1000000000.0;

class Task implements Callable<String> {
    private final String name;

    Task(String name) {
        this.name = name;
    }

    @Override
    public String call() {
        try {
            System.out.printf("%s : task start (%f sec.)%n", name, elapsedTime.getAsDouble());
            TimeUnit.SECONDS.sleep(2);

            return "abcd";
        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
            return null;
        } finally {
            System.out.printf("%s : task end (%f sec.)%n", name, elapsedTime.getAsDouble());
        }
    }
}

try (final var executorService = Executors.newSingleThreadExecutor()) {
    System.out.println("submit A");
    final var futureA = executorService.submit(new Task("A"));

    TimeUnit.SECONDS.sleep(1);

    System.out.println("submit B");
    final var futureB = executorService.submit(new Task("B"));

    System.out.println("-- cancel tasks --");

    final var retA = futureA.cancel(false);
    System.out.printf("cancel A : ret = %b (%f sec.)%n", retA, elapsedTime.getAsDouble());

    final var retB = futureB.cancel(false);
    System.out.printf("cancel B : ret = %b (%f sec.)%n", retB, elapsedTime.getAsDouble());
}

System.out.println("-- end --");

// 結果
// ↓
//submit A
//A : task start (0.002960 sec.)
//submit B
//-- cancel tasks --
//cancel A : ret = true (1.014476 sec.)
//cancel B : ret = true (1.014648 sec.)
//A : task end (2.016125 sec.)
//-- end --

// ※mayInterruptIfRunning = false では割込みは発生しません。
//  また、サブミットだけで開始されていなかったタスクBは、開始されないまま終了します。
final long current = System.nanoTime();
final DoubleSupplier elapsedTime = () -> (System.nanoTime() - current) / 1000000000.0;

try (final var executorService = Executors.newSingleThreadExecutor()) {
    final var future = executorService.submit(() -> {
        try {
            System.out.printf("task start (%f sec.)%n", elapsedTime.getAsDouble());
            TimeUnit.SECONDS.sleep(2);

            return "abcd";
        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
            return null;
        } finally {
            System.out.printf("task end (%f sec.)%n", elapsedTime.getAsDouble());
        }
    });

    TimeUnit.SECONDS.sleep(1);

    System.out.printf("cancel! (%f sec.)%n", elapsedTime.getAsDouble());
    final var ret = future.cancel(true);

    System.out.printf("cancel ret = %b%n", ret);
}

// 結果
// ↓
//task start (0.003275 sec.)
//cancel! (1.004838 sec.)
//Interrupted!
//task end (1.005646 sec.)
//cancel ret = true

// ※mayInterruptIfRunning = true は割込みを発生させます。
final long current = System.nanoTime();
final DoubleSupplier elapsedTime = () -> (System.nanoTime() - current) / 1000000000.0;

try (final var executorService = Executors.newSingleThreadExecutor()) {
    final var future = executorService.submit(() -> {
        try {
            System.out.printf("task start (%f sec.)%n", elapsedTime.getAsDouble());
            TimeUnit.SECONDS.sleep(2);

            return "abcd";
        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
            return null;
        } finally {
            System.out.printf("task end (%f sec.)%n", elapsedTime.getAsDouble());
        }
    });

    // タスクが完了するのを待ちます。
    System.out.println("get = " + future.get());

    final var ret = future.cancel(true);
    System.out.printf("cancel ret = %b (%f sec.)%n", ret, elapsedTime.getAsDouble());
}

// 結果
// ↓
//task start (0.002477 sec.)
//task end (2.009747 sec.)
//get = abcd
//cancel ret = false (2.011178 sec.)

// ※すでに終了しているタスクに対して cancel すると false を返します。

default Throwable exceptionNow ()

待機せずにタスクによってスローされた例外を返します。

try (final var executorService = Executors.newSingleThreadExecutor()) {
    final var futures = new ArrayList<Future<String>>();

    futures.add(executorService.submit(() -> "abc"));
    futures.add(executorService.submit(() -> "XYZ"));
    futures.add(executorService.submit(() -> {
        throw new IllegalStateException("Fail!");
    }));
    futures.add(executorService.submit(() -> "1234"));

    final var results = futures.stream()
            .filter(f -> f.state() == Future.State.SUCCESS)
            .map(Future::resultNow)
            .toList();

    System.out.println("results = " + results);

    final var exceptions = futures.stream()
            .filter(f -> f.state() == Future.State.FAILED)
            .map(Future::exceptionNow)
            .toList();

    System.out.println("exceptions = " + exceptions);
}

// 結果
// ↓
//results = [abc, XYZ, 1234]
//exceptions = [java.lang.IllegalStateException: Fail!]

V get ()

必要に応じて計算が完了するまで待機し、その後、計算結果を取得します。

try (final var executorService = Executors.newSingleThreadExecutor()) {
    final var future = executorService.submit(() -> {
        try {
            System.out.println("task start");
            TimeUnit.SECONDS.sleep(2);

            return "abcd";
        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
            return null;
        } finally {
            System.out.println("task end");
        }
    });

    TimeUnit.SECONDS.sleep(1);

    System.out.println("-- get start --");
    final var ret = future.get();

    System.out.println("-- get end --");
    System.out.println("ret = " + ret);
}

// 結果
// ↓
//task start
//-- get start --
//task end
//-- get end --
//ret = abcd
try (final var executorService = Executors.newSingleThreadExecutor()) {
    final var future = executorService.submit(() -> {
        try {
            System.out.println("task start");
            TimeUnit.SECONDS.sleep(2);

            throw new IllegalStateException("Fail!");
        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
            return null;
        } finally {
            System.out.println("task end");
        }
    });

    TimeUnit.SECONDS.sleep(1);

    try {
        System.out.println("-- get start --");
        final var ret = future.get();

        System.out.println("-- get end --");
        System.out.println("ret = " + ret);
    } catch (ExecutionException e) {
        System.out.println("ExecutionException! : " + e.getMessage());
    }
}

// 結果
// ↓
//task start
//-- get start --
//task end
//ExecutionException! : java.lang.IllegalStateException: Fail!
try (final var executorService = Executors.newScheduledThreadPool(2)) {
    final var future = executorService.submit(() -> {
        try {
            System.out.println("task start");
            TimeUnit.SECONDS.sleep(3);

            return "abcd";
        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
            return null;
        } finally {
            System.out.println("task end");
        }
    });

    // 2秒後にキャンセルします。
    executorService.schedule(() -> {
        System.out.println("future.cancel");
        future.cancel(true);
    }, 2, TimeUnit.SECONDS);

    try {
        System.out.println("-- get start --");
        final var ret = future.get();

        System.out.println("-- get end --");
        System.out.println("ret = " + ret);
    } catch (CancellationException e) {
        System.out.println("CancellationException!");
    }
}

// 結果
// ↓
//task start
//-- get start --
//future.cancel
//Interrupted!
//CancellationException!
//task end

V get (long timeout, TimeUnit unit)

必要に応じて、最大で指定された時間、計算が完了するまで待機し、その後、計算結果が利用可能な場合は結果を取得します。

try (final var executorService = Executors.newSingleThreadExecutor()) {
    final var future = executorService.submit(() -> {
        try {
            System.out.println("task start");
            TimeUnit.SECONDS.sleep(2);

            return "abcd";
        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
            return null;
        } finally {
            System.out.println("task end");
        }
    });

    TimeUnit.SECONDS.sleep(1);

    try {
        System.out.println("-- get start --");
        final var ret = future.get(3, TimeUnit.SECONDS);

        System.out.println("-- get end --");
        System.out.println("ret = " + ret);
    } catch (TimeoutException e) {
        System.out.println("TimeoutException!");
    }
}

// 結果
// ↓
//task start
//-- get start --
//task end
//-- get end --
//ret = abcd
try (final var executorService = Executors.newSingleThreadExecutor()) {
    final var future = executorService.submit(() -> {
        try {
            System.out.println("task start");
            TimeUnit.SECONDS.sleep(3);

            return "abcd";
        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
            return null;
        } finally {
            System.out.println("task end");
        }
    });

    TimeUnit.SECONDS.sleep(1);

    try {
        System.out.println("-- get start --");
        final var ret = future.get(1, TimeUnit.SECONDS);

        System.out.println("-- get end --");
        System.out.println("ret = " + ret);
    } catch (TimeoutException e) {
        System.out.println("TimeoutException!");
    }
}

// 結果
// ↓
//task start
//-- get start --
//TimeoutException!
//task end

boolean isCancelled ()

このタスクが正常に完了する前に取り消された場合はtrueを返します。

try (final var executorService = Executors.newSingleThreadExecutor()) {
    final var future = executorService.submit(() -> {
        try {
            System.out.println("-- task start --");
            TimeUnit.SECONDS.sleep(2);

            return "abcd";
        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
            return null;
        } finally {
            System.out.println("-- task end --");
        }
    });

    TimeUnit.SECONDS.sleep(1);

    System.out.println("isCancelled = " + future.isCancelled());
    System.out.println("isDone = " + future.isDone());
    System.out.println("state = " + future.state());

    // タスクが完了するのを待ちます。
    System.out.println("get = " + future.get());

    System.out.println("isCancelled = " + future.isCancelled());
    System.out.println("isDone = " + future.isDone());
    System.out.println("state = " + future.state());

    // タスク完了後にキャンセルしても isCancelled は true になりません。
    System.out.println("----");
    System.out.println("cancel = " + future.cancel(false));
    System.out.println("isCancelled = " + future.isCancelled());
}

// 結果
// ↓
//-- task start --
//isCancelled = false
//isDone = false
//state = RUNNING
//-- task end --
//isCancelled = false
//isDone = true
//state = SUCCESS
//----
//cancel = false
//isCancelled = false
try (final var executorService = Executors.newSingleThreadExecutor()) {
    final var future = executorService.submit(() -> {
        try {
            System.out.println("-- task start --");
            TimeUnit.SECONDS.sleep(2);

            return "abcd";
        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
            return null;
        } finally {
            System.out.println("-- task end --");
        }
    });

    TimeUnit.SECONDS.sleep(1);

    System.out.println("isCancelled = " + future.isCancelled());
    System.out.println("isDone = " + future.isDone());
    System.out.println("state = " + future.state());

    System.out.println("----");
    System.out.println("cancel = " + future.cancel(false));

    System.out.println("isCancelled = " + future.isCancelled());
    System.out.println("isDone = " + future.isDone());
    System.out.println("state = " + future.state());
}

// 結果
// ↓
//-- task start --
//isCancelled = false
//isDone = false
//state = RUNNING
//----
//cancel = true
//isCancelled = true
//isDone = true
//state = CANCELLED
//-- task end --
try (final var executorService = Executors.newSingleThreadExecutor()) {
    final var future = executorService.submit(() -> {
        try {
            System.out.println("-- task start --");
            TimeUnit.SECONDS.sleep(2);

            throw new IllegalStateException("Fail!");
        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
            return null;
        } finally {
            System.out.println("-- task end --");
        }
    });

    TimeUnit.SECONDS.sleep(1);

    System.out.println("isCancelled = " + future.isCancelled());
    System.out.println("isDone = " + future.isDone());
    System.out.println("state = " + future.state());

    try {
        System.out.println("get = " + future.get());
    } catch (ExecutionException e) {
        System.out.println("ExecutionException! : " + e.getMessage());
    }

    System.out.println("isCancelled = " + future.isCancelled());
    System.out.println("isDone = " + future.isDone());
    System.out.println("state = " + future.state());
}

// 結果
// ↓
//-- task start --
//isCancelled = false
//isDone = false
//state = RUNNING
//-- task end --
//ExecutionException! : java.lang.IllegalStateException: Fail!
//isCancelled = false
//isDone = true
//state = FAILED

boolean isDone ()

このタスクが完了した場合はtrueを返します。

このメソッドの使用例は、isCancelled() にまとめて記載しました。
そちらのAPI使用例をご参照ください。

default V resultNow ()

計算された結果を待たずに返します。

このメソッドの使用例は、exceptionNow() にまとめて記載しました。
そちらのAPI使用例をご参照ください。

default Future.State state ()

計算状態を返します。

このメソッドの使用例は、isCancelled() にまとめて記載しました。
そちらのAPI使用例をご参照ください。


関連記事

ページの先頭へ