Встречается на 31% собеседований по Java

Что такое ExecutorService

ExecutorService — это интерфейс из пакета java.util.concurrent, который предоставляет фреймворк для асинхронного выполнения задач. Он позволяет управлять потоками и задачами без необходимости явно создавать и управлять потоками вручную, что делает код более читаемым, упрощает работу с многопоточностью и повышает производительность приложения.

Как это работает

В многопоточных приложениях часто возникает необходимость выполнять задачи параллельно или асинхронно. Вместо того чтобы каждый раз создавать новые потоки вручную (что неэффективно и усложняет код), ExecutorService предоставляет удобные методы для выполнения задач в уже существующем пуле потоков. Это позволяет повторно использовать потоки и управлять ими эффективно.

ExecutorService создается через статические методы класса Executors:

  • newFixedThreadPool(int n) — пул с фиксированным числом потоков.
  • newCachedThreadPool() — кэширующий пул: создает новые потоки по мере необходимости и переиспользует освободившиеся.
  • newSingleThreadExecutor() — пул для последовательного выполнения задач в одном потоке.

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

  • execute(Runnable) — для задач без результата.
  • submit(Callable<T>) — для задач, возвращающих результат (возвращает Future<T>).

Также доступны методы управления жизненным циклом: shutdown() — останавливает прием новых задач и завершает уже запущенные; shutdownNow() — пытается остановить все выполняющиеся задачи.

Пример

java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorExample {
    public static void main(String[] args) {
        // Создаем пул из 10 потоков
        ExecutorService executor = Executors.newFixedThreadPool(10);

        // Отправляем задачу на выполнение
        executor.submit(() -> {
            System.out.println("Асинхронная задача " + Thread.currentThread().getName());
        });

        // Завершаем работу ExecutorService после выполнения всех задач
        executor.shutdown();
    }
}

В этом примере задача выводит имя потока, в котором она выполняется. Пул из 10 потоков позволяет выполнять до 10 задач одновременно.

Подводные камни

  • Не забывайте завершать ExecutorService: если не вызвать shutdown(), потоки будут продолжать работать, и приложение не завершится.
  • Используйте submit() вместо execute(), если нужен результат выполнения или контроль над задачей через Future.
  • Будьте осторожны с newCachedThreadPool(): он может создать неограниченное количество потоков при большом количестве задач, что приведет к перегрузке системы.
  • Для длительных задач лучше использовать newFixedThreadPool() с ограниченным числом потоков, чтобы избежать неконтролируемого роста ресурсов.

Когда использовать

ExecutorService применяется в любых сценариях, где требуется асинхронное выполнение задач: обработка запросов на сервере, параллельные вычисления, фоновые задачи в приложениях с графическим интерфейсом. Он особенно полезен, когда нужно ограничить количество одновременно выполняемых потоков или переиспользовать потоки для повышения производительности.

Коротко

  • ExecutorService — интерфейс для управления пулом потоков и асинхронным выполнением задач.
  • Создается через Executors (например, newFixedThreadPool, newCachedThreadPool).
  • Задачи отправляются через execute() (без результата) или submit() (с результатом).
  • Обязательно вызывайте shutdown() для корректного завершения работы.
как отвечать на вопрос
пример собеседования
фреймворки на собеседовании
типичные вопросы junior
интервью вопросы и ответы