Вопрос с собеседования · Java

Что такое Fork/Join framework и work stealing?

SeniorМногопоточность
Коротко

Fork/Join — рекурсивное деление задачи на подзадачи (fork) с последующим объединением результатов (join). Work stealing: у каждого рабочего потока своя двусторонняя очередь, а освободившийся поток крадёт задачи с хвоста чужой очереди — нагрузка балансируется сама.

  • RecursiveTask возвращает результат, RecursiveAction — нет
  • Для CPU-bound задач без блокировок
  • На нём работают parallel stream и async-методы CompletableFuture (commonPool)

А ещё Порог деления: слишком мелкие задачи съедают выигрыш накладными расходами

Подробно

Модель. Задача проверяет размер: мала — решает напрямую, иначе делится на части, одну отправляет fork(), другую решает сама, затем join() собирает результат.

class Sum extends RecursiveTask<Long> {
    protected Long compute() {
        if (hi - lo < 10_000) return directSum();
        Sum left = new Sum(arr, lo, mid);
        left.fork();
        long right = new Sum(arr, mid, hi).compute();
        return left.join() + right;
    }
}

Work stealing. Каждый поток ForkJoinPool кладёт свои подзадачи в собственную деку и берёт их с головы (LIFO — горячие данные в кэше). Свободный поток крадёт у других с хвоста — там самые крупные, ещё не разделённые задачи. Нет единой очереди, за которую бьются все.

Ограничения:

  • задачи не должны блокироваться: заблокированный поток не делает работу, а пул фиксированного размера;
  • выигрыш только при достаточном объёме и разумном пороге деления;
  • ForkJoinPool.commonPool() общий на всю JVM — его используют parallel stream и CompletableFuture без своего executor.

Что хотят услышать

  • Рекурсивное деление и объединение.
  • Механика work stealing и зачем дека.
  • Для каких задач подходит и связь с commonPool.

Частые ошибки

  • Запускать долгий blocking IO в common ForkJoinPool.
  • Делить задачу слишком мелко и тратить время на overhead.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✗Пул потоков для блокирующих задач ввода-вывода вроде запросов к базе
  • ✗Фреймворк, который запускает каждую подзадачу в отдельном новом потоке операционной системы и ждёт их через join
  • ✓Рекурсивное деление и кража задач из чужих очередей
  • ✗Общая очередь, из которой все потоки берут задачи строго по порядку

Что спросят дальше

  • Как parallelStream связан с ForkJoinPool?
  • Когда parallelStream вреден?

Разбор темы

Связанные вопросы

Партнёр платформы

Разбор собеседования с sotto

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования