広告

Java : FutureTask - API使用例

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


概要

取消し可能な非同期計算です。 このクラスはFutureのベース実装を提供し、計算の開始と取消し、計算が完了したかどうかの問合せ、計算結果の取得などを行うメソッドを持っています。 結果は、計算の完了時にのみ取得できます。計算がまだ完了していないうちはgetメソッドがブロックします。

クラス構成

基本的には Futureインタフェース と同じです。
ただし、いくつかオーバライドすると便利なメソッドが追加されています。

FutureTaskはそれ自体が Runnable でもあるので、ExecutorService に直接 submit できます。

final var executorService = Executors.newSingleThreadExecutor();
try {
    final var futureTask = new FutureTask<>(() -> {
        System.out.println("task run");
    }, "abcd");

    executorService.submit(futureTask);

    System.out.println("get : " + futureTask.get());

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task run
//get : abcd
//term : true

コンストラクタ

FutureTask (Runnable runnable, V result)

指定されたRunnableを実行時に実行し、かつ正常に完了すると指定された結果をgetで返すFutureTaskを作成します。

final var executorService = Executors.newSingleThreadExecutor();
try {
    final var futureTask = new FutureTask<>(() -> {
        System.out.println("task run");
    }, "abcd");

    executorService.submit(futureTask);

    System.out.println("get : " + futureTask.get());

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task run
//get : abcd
//term : true

FutureTask (Callable<V> callable)

指定されたCallableを実行時に実行するFutureTaskを作成します。

final var executorService = Executors.newSingleThreadExecutor();
try {
    final var futureTask = new FutureTask<>(() -> {
        System.out.println("task run");
        return "abcd";
    });

    executorService.submit(futureTask);

    System.out.println("get : " + futureTask.get());

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task run
//get : abcd
//term : true

メソッド

boolean cancel (boolean mayInterruptIfRunning)

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

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

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

final var executorService = Executors.newSingleThreadExecutor();
try {
    final var futureTask = new FutureTask<>(() -> {
        try {
            System.out.println("task start : " + getTime.getAsDouble() + " sec.");
            TimeUnit.SECONDS.sleep(2);

            return "abcd";

        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
            return null;
        } finally {
            System.out.println("task end : " + getTime.getAsDouble() + " sec.");
        }
    });

    executorService.submit(futureTask);

    TimeUnit.SECONDS.sleep(1);

    // mayInterruptIfRunning = false
    final var ret = futureTask.cancel(false);
    System.out.println("cancel = " + ret + " : " + getTime.getAsDouble() + " sec.");

} finally {
    executorService.shutdown();
    System.out.println("shutdown : " + getTime.getAsDouble() + " sec.");
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term = " + ret + " : " + getTime.getAsDouble() + " sec.");

// 結果
// ↓
//task start : 0.0030879 sec.
//cancel = true : 1.0165037 sec.
//shutdown : 1.0204428 sec.
//task end : 2.0135346 sec.
//term = true : 2.0140798 sec.

// ※mayInterruptIfRunning = false では割込みは発生しません。
final long current = System.nanoTime();
final DoubleSupplier getTime = () -> (System.nanoTime() - current) / 1000000000.0;

final var executorService = Executors.newSingleThreadExecutor();
try {
    final var futureTask = new FutureTask<>(() -> {
        try {
            System.out.println("task start : " + getTime.getAsDouble() + " sec.");
            TimeUnit.SECONDS.sleep(2);

            return "abcd";

        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
            return null;
        } finally {
            System.out.println("task end : " + getTime.getAsDouble() + " sec.");
        }
    });

    executorService.submit(futureTask);

    TimeUnit.SECONDS.sleep(1);

    // mayInterruptIfRunning = true
    final var ret = futureTask.cancel(true);
    System.out.println("cancel = " + ret + " : " + getTime.getAsDouble() + " sec.");

} finally {
    executorService.shutdown();
    System.out.println("shutdown : " + getTime.getAsDouble() + " sec.");
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term = " + ret + " : " + getTime.getAsDouble() + " sec.");

// 結果
// ↓
//task start : 0.0035929 sec.
//Interrupted!
//task end : 1.0059904 sec.
//cancel = true : 1.005947 sec.
//shutdown : 1.0097252 sec.
//term = true : 1.0098963 sec.

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

final var executorService = Executors.newSingleThreadExecutor();
try {
    final var futureTask = new FutureTask<>(() -> {
        try {
            System.out.println("task start : " + getTime.getAsDouble() + " sec.");
            TimeUnit.SECONDS.sleep(2);

            return "abcd";

        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
            return null;
        } finally {
            System.out.println("task end : " + getTime.getAsDouble() + " sec.");
        }
    });

    executorService.submit(futureTask);

    // タスクが完了するのを待ちます。
    TimeUnit.SECONDS.sleep(3);

    final var ret = futureTask.cancel(true);
    System.out.println("cancel = " + ret + " : " + getTime.getAsDouble() + " sec.");

} finally {
    executorService.shutdown();
    System.out.println("shutdown : " + getTime.getAsDouble() + " sec.");
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term = " + ret + " : " + getTime.getAsDouble() + " sec.");

// 結果
// ↓
//task start : 0.0022581 sec.
//task end : 2.0066302 sec.
//cancel = false : 3.0161829 sec.
//shutdown : 3.0202056 sec.
//term = true : 3.0203844 sec.

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

protected void done ()

このタスクの状態が(正常に、または取消しによって) isDoneに切り替わるときに呼び出されるprotectedメソッドです。

※API仕様には明記されていませんが、正常に完了したときとcancelされたときで、doneが実行されるスレッドが変わるようです。ご注意ください。

final var executorService = Executors.newSingleThreadExecutor();
try {
    final var futureTask = new FutureTask<>(() -> {
        try {
            System.out.println("-- task start --");
            System.out.println("task thread id : " + Thread.currentThread().getId());

            TimeUnit.SECONDS.sleep(1);
            return "abcd";

        } finally {
            System.out.println("-- task end --");
        }
    }) {
        @Override
        protected void done() {
            System.out.println("done!");
            System.out.println("done thread id : " + Thread.currentThread().getId());
        }
    };

    System.out.println("main thread id : " + Thread.currentThread().getId());
    executorService.submit(futureTask);

    System.out.println("get : " + futureTask.get());

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//main thread id : 1
//-- task start --
//task thread id : 19
//-- task end --
//done!
//get : abcd
//done thread id : 19
//term : true
final var executorService = Executors.newSingleThreadExecutor();
try {
    final var futureTask = new FutureTask<>(() -> {
        try {
            System.out.println("-- task start --");
            System.out.println("task thread id : " + Thread.currentThread().getId());

            TimeUnit.SECONDS.sleep(2);

            return "abcd";
        } finally {
            System.out.println("-- task end --");
        }
    }) {
        @Override
        protected void done() {
            System.out.println("done!");
            System.out.println("done thread id : " + Thread.currentThread().getId());
        }
    };

    System.out.println("main thread id : " + Thread.currentThread().getId());
    executorService.submit(futureTask);

    TimeUnit.SECONDS.sleep(1);

    futureTask.cancel(true);
    System.out.println("isCancelled : " + futureTask.isCancelled());

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//main thread id : 1
//-- task start --
//task thread id : 19
//-- task end --
//done!
//done thread id : 1
//isCancelled : true
//term : true

V get ()

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

final var executorService = Executors.newSingleThreadExecutor();
try {
    final var futureTask = new FutureTask<>(() -> {
        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");
        }
    });

    executorService.submit(futureTask);

    TimeUnit.SECONDS.sleep(1);

    System.out.println("-- get start --");

    final var ret = futureTask.get();

    System.out.println("-- get end --");
    System.out.println("future ret : " + ret);

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

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

            throw new IllegalStateException("Exception!");

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

    executorService.submit(futureTask);

    TimeUnit.SECONDS.sleep(1);

    System.out.println("-- get start --");

    final var ret = futureTask.get();

    System.out.println("-- get end --");
    System.out.println("future ret : " + ret);

} catch (ExecutionException e) {
    System.out.println("ExecutionException! : " + e.getMessage());
} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task start
//-- get start --
//task end
//ExecutionException! : java.lang.IllegalStateException: Exception!
//term : true
final var executorService = Executors.newScheduledThreadPool(2);
try {
    final var futureTask = new FutureTask<>(() -> {
        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");
        }
    });

    executorService.submit(futureTask);

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

    TimeUnit.SECONDS.sleep(1);

    System.out.println("-- get start --");

    final var ret = futureTask.get();

    System.out.println("-- get end --");
    System.out.println("future ret : " + ret);

} catch (CancellationException e) {
    System.out.println("CancellationException!");
} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task start
//-- get start --
//future cancel
//Interrupted!
//task end
//CancellationException!
//term : true

V get (long timeout, TimeUnit unit)

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

get() の使用例もあわせてご参照ください。

final var executorService = Executors.newSingleThreadExecutor();
try {
    final var futureTask = new FutureTask<>(() -> {
        try {
            System.out.println("task start");
            TimeUnit.SECONDS.sleep(3);
            return "abcd";
        } finally {
            System.out.println("task end");
        }
    });

    executorService.submit(futureTask);

    TimeUnit.SECONDS.sleep(1);

    System.out.println("-- get start --");

    final var ret = futureTask.get(5, TimeUnit.SECONDS);

    System.out.println("-- get end --");
    System.out.println("future ret : " + ret);

} catch (TimeoutException e) {
    System.out.println("TimeoutException!");
} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task start
//-- get start --
//task end
//-- get end --
//future ret : abcd
//term : true
final var executorService = Executors.newSingleThreadExecutor();
try {
    final var futureTask = new FutureTask<>(() -> {
        try {
            System.out.println("task start");
            TimeUnit.SECONDS.sleep(3);
            return "abcd";
        } finally {
            System.out.println("task end");
        }
    });

    executorService.submit(futureTask);

    TimeUnit.SECONDS.sleep(1);

    System.out.println("-- get start --");

    final var ret = futureTask.get(1, TimeUnit.SECONDS);

    // ↓ここは呼び出されません。
    System.out.println("-- get end --");
    System.out.println("future ret : " + ret);

} catch (TimeoutException e) {
    System.out.println("TimeoutException!");
} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task start
//-- get start --
//TimeoutException!
//task end
//term : true

boolean isCancelled ()

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

final var executorService = Executors.newSingleThreadExecutor();
try {
    final var futureTask = new FutureTask<>(() -> {
        try {
            System.out.println("task start");
            TimeUnit.SECONDS.sleep(2);
            return "abcd";
        } finally {
            System.out.println("task end");
        }
    });

    executorService.submit(futureTask);

    TimeUnit.SECONDS.sleep(1);

    System.out.println("-- before cancel -- : " + futureTask.isCancelled());

    futureTask.cancel(false);

    System.out.println("-- after cancel -- : " + futureTask.isCancelled());

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task start
//-- before cancel -- : false
//-- after cancel -- : true
//task end
//term : true
final var executorService = Executors.newSingleThreadExecutor();
try {
    final var futureTask = new FutureTask<>(() -> {
        try {
            System.out.println("task start");
            TimeUnit.SECONDS.sleep(2);
            return "abcd";
        } finally {
            System.out.println("task end");
        }
    });

    executorService.submit(futureTask);

    TimeUnit.SECONDS.sleep(1);

    System.out.println("-- before cancel -- : " + futureTask.isCancelled());

    // タスクが完了するのを待ちます。
    TimeUnit.SECONDS.sleep(2);

    futureTask.cancel(false);

    // タスクの完了後にキャンセルをしても、isCancelledはtrueになりません。
    System.out.println("-- after cancel -- : " + futureTask.isCancelled());

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task start
//-- before cancel -- : false
//task end
//-- after cancel -- : false
//term : true

boolean isDone ()

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

final var executorService = Executors.newSingleThreadExecutor();
try {
    final var futureTask = new FutureTask<>(() -> {
        try {
            System.out.println("task start");
            TimeUnit.SECONDS.sleep(2);
            return "abcd";
        } finally {
            System.out.println("task end");
        }
    });

    executorService.submit(futureTask);

    TimeUnit.SECONDS.sleep(1);

    System.out.println("-- isDone 1 -- : " + futureTask.isDone());

    // タスクが完了するのを待ちます。
    TimeUnit.SECONDS.sleep(2);

    System.out.println("-- isDone 2 -- : " + futureTask.isDone());

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task start
//-- isDone 1 -- : false
//task end
//-- isDone 2 -- : true
//term : true
final var executorService = Executors.newSingleThreadExecutor();
try {
    final var futureTask = new FutureTask<>(() -> {
        try {
            System.out.println("task start");
            TimeUnit.SECONDS.sleep(2);
            return "abcd";
        } finally {
            System.out.println("task end");
        }
    });

    executorService.submit(futureTask);

    TimeUnit.SECONDS.sleep(1);

    System.out.println("-- isDone 1 -- : " + futureTask.isDone());

    futureTask.cancel(false);

    // タスクが終了していなくても、キャンセルされた直後にDoneとなります。
    System.out.println("-- isDone 2 -- : " + futureTask.isDone());

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task start
//-- isDone 1 -- : false
//-- isDone 2 -- : true
//task end
//term : true

void run ()

取り消されていなければ、このFutureに計算結果を設定します。

final var futureTask = new FutureTask<>(() -> {
    System.out.println("Run!");
    return "abcd";
});

// ExecutorServiceを使わずに直接実行します。
futureTask.run();

System.out.println("isDone : " + futureTask.isDone());

final var ret = futureTask.get();
System.out.println("get ret : " + ret);

// 結果
// ↓
//Run!
//isDone : true
//get ret : abcd

protected boolean runAndReset ()

結果を設定せずに計算を実行し、このfutureを初期状態にリセットします。計算時に例外が発生した場合または計算が取り消された場合は失敗します。

final var runnable = new Runnable() {
    private int count;

    @Override
    public void run() {
        count++;
        System.out.println("count : " + count);
    }
};

final var task = new FutureTask<>(runnable, "abcd") {
    @Override
    public void run() {
        final var ret = runAndReset();
        System.out.println("runAndReset ret : " + ret);
    }
};

task.run();
System.out.println("isDone : " + task.isDone());

task.run();
System.out.println("isDone : " + task.isDone());

task.run();
System.out.println("isDone : " + task.isDone());

// 結果
// ↓
//count : 1
//runAndReset ret : true
//isDone : false
//count : 2
//runAndReset ret : true
//isDone : false
//count : 3
//runAndReset ret : true
//isDone : false
final var task = new FutureTask<>(() -> {
    throw new IllegalStateException("Exception!");
}) {
    @Override
    public void run() {
        final var ret = runAndReset();
        System.out.println("runAndReset ret : " + ret);
    }
};

task.run();
System.out.println("isDone : " + task.isDone());

// 結果
// ↓
//runAndReset ret : false
//isDone : true

protected void set (V v)

このfutureが設定済みの場合または取り消された場合を除き、このfutureの結果に指定された値を設定します。

final var futureTask = new FutureTask<>(() -> {
    try {
        System.out.println("task start");
        return "abcd";
    } finally {
        System.out.println("task end");
    }
}) {
    @Override
    protected void set(String s) {
        super.set(s);
        System.out.println("set : " + s);
    }
};

futureTask.run();

System.out.println("isDone : " + futureTask.isDone());

// 結果
// ↓
//task start
//task end
//set : abcd
//isDone : true

protected void setException (Throwable t)

このFutureが設定済みの場合または取り消された場合を除き、このFutureがExecutionExceptionと、その理由として指定されたスロー可能オブジェクトを報告するようになります。

final var futureTask = new FutureTask<>(() -> {
    try {
        System.out.println("task start");
        throw new IllegalStateException("Exception!");
    } finally {
        System.out.println("task end");
    }
}) {
    @Override
    protected void setException(Throwable t) {
        super.setException(t);
        System.out.println("setException : " + t);
    }
};

futureTask.run();

System.out.println("isDone : " + futureTask.isDone());

// 結果
// ↓
//task start
//task end
//setException : java.lang.IllegalStateException: Exception!
//isDone : true

String toString ()

このFutureTaskの文字列表現を返します。

final var futureTask = new FutureTask<>(() -> "abcd");

final var ret1 = futureTask.toString();
System.out.println("before run : " + ret1);

futureTask.run();

final var ret2 = futureTask.toString();
System.out.println("after run : " + ret2);

// 結果
// ↓
//before run : java.util.concurrent.FutureTask@c05fddc[Not completed, task = ...]
//after run : java.util.concurrent.FutureTask@c05fddc[Completed normally]

関連記事

ページの先頭へ