FutureTask
FutureTask<V> реализует одновременно Runnable и Future. Это мост между задачей, которую можно запустить, и объектом, через который получают ее результат.
FutureTask<Integer> task = new FutureTask<>(() -> calculate());
Thread thread = new Thread(task, "calculator");
thread.start();
Integer result = task.get();Тот же объект можно передать в Executor.execute(task). Вызывать run() несколько раз допустимо, но вычисление выполнится только один раз: после завершения последующие вызовы ничего не пересчитают.
Вариант с Runnable
FutureTask<String> task =
new FutureTask<>(() -> writeReport(), "written");Здесь заданное значение "written" становится результатом после нормального завершения Runnable.
Расширение
Protected-метод done() вызывается после перехода в конечное состояние:
final class LoggedTask<V> extends FutureTask<V> {
LoggedTask(Callable<V> callable) {
super(callable);
}
@Override
protected void done() {
// Не блокироваться надолго; состояние уже terminal.
}
}При отмене действуют те же ограничения, что у Future: interrupt — кооперативный сигнал.
В обычном коде submit(Callable) уже создает внутреннюю FutureTask-подобную обертку, поэтому ручной класс нужен редко: когда задача должна быть одновременно передана как Runnable и опубликована как Future, либо нужен hook done().
На собеседовании
- Какие интерфейсы соединяет FutureTask?
RunnableиFutureчерезRunnableFuture. - Выполнится ли Callable дважды после двух
run()? Нет. - Когда вызывается
done()? После результата, ошибки или отмены. - Чем FutureTask отличается от CompletableFuture? Первая оборачивает одно запускаемое вычисление, вторая предназначена для композиции стадий.