Что такое FutureTask в Java и для чего он используется?

«Что такое FutureTask в Java и для чего он используется?» — вопрос из категории Java Core, который задают на 22% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

FutureTask — это конкретная реализация интерфейсов Future<V> и Runnable в Java. Это обёртка для отложенной асинхронной задачи (Callable или Runnable), которая позволяет управлять её выполнением, проверять статус и получать результат.

Ключевые возможности:

  • Представляет вычисление, которое может быть выполнено асинхронно.
  • Реализует Runnable, поэтому может быть передан в Executor или запущен в отдельном потоке.
  • Реализует Future, предоставляя методы get(), cancel(), isDone().

Пример использования с Callable:

import java.util.concurrent.*;

// Задача, возвращающая результат
Callable<String> computeTask = () -> {
    Thread.sleep(2000); // Имитация долгой работы
    return "Result of computation";
};

// Создание FutureTask
FutureTask<String> futureTask = new FutureTask<>(computeTask);

// Запуск в отдельном потоке
new Thread(futureTask).start();

// ... основной поток может делать другую работу ...

try {
    // get() блокирует поток до завершения задачи и возвращает результат
    String result = futureTask.get();
    System.out.println(result); // Result of computation
} catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
}

Пример использования с Runnable (результат можно задать явно):

Runnable runnableTask = () -> System.out.println("Task running");
FutureTask<String> futureTaskWithResult = new FutureTask<>(runnableTask, "Predefined Result");
new Thread(futureTaskWithResult).start();
String result = futureTaskWithResult.get(); // Вернёт "Predefined Result"

Основные методы:

  • get(): Блокирует поток до завершения задачи, затем возвращает результат.
  • get(long timeout, TimeUnit unit): Блокирует с таймаутом.
  • cancel(boolean mayInterruptIfRunning): Пытается отменить выполнение задачи.
  • isDone(): Проверяет, завершена ли задача (нормально, с ошибкой или отменой).

Типичное применение: Ручное управление выполнением задач в пуле потоков или когда нужно обернуть Callable в Runnable для передачи в API, принимающий только Runnable.