Gymterview
middle

Расскажите о параллельной обработке в Java 8

Параллельные стримы позволяют автоматически распределить обработку данных по нескольким ядрам процессора. Данные разбиваются на части, каждая часть обрабатывается в отдельном потоке, а затем результаты объединяются. Под капотом используется общий ForkJoinPool (доступен через ForkJoinPool.commonPool()).

Создание параллельного стрима

Пример
// Из коллекции
collection.parallelStream();

// Из существующего стрима
stream.parallel();

// Проверка
stream.isParallel(); // true/false

Переключение между режимами

Пример
collection.stream()
    .peek(...)        // последовательно
    .parallel()
    .map(...)         // параллельно
    .sequential()
    .reduce(...);     // последовательно

Когда параллельные стримы эффективны

Фактор Хорошо Плохо
Размер данных Большие объёмы (>10K элементов) Малые объёмы
Структура данных ArrayList, массивы (легко разбить) LinkedList (трудно разбить)
Тип данных Примитивы Объекты с тяжёлым autoboxing
Тип операций Короткие CPU-bound операции Долгие I/O операции, блокировки
Порядок Не важен Важен (forEachOrdered добавляет overhead)

Важные ограничения

  • Все параллельные стримы в JVM делят один ForkJoinPool — долгая операция в одном стриме может заблокировать другие
  • Для сохранения порядка используйте forEachOrdered() вместо forEach()
  • unordered() может повысить производительность, если порядок не важен
  • На одноядерной машине параллельный стрим выполняется последовательно
Пример с unordered
collection.parallelStream()
    .sorted()
    .unordered()
    .collect(Collectors.toList());

На собеседовании: не говорите, что параллельные стримы «всегда быстрее». Интервьюер ожидает понимания компромиссов: overhead на разбиение и объединение данных, общий ForkJoinPool, проблемы с LinkedList. Золотое правило — измерять (benchmark), а не угадывать.