Ответ
Параллельный стрим (parallelStream()) по умолчанию использует потоки из общего пула (common pool) ForkJoinPool. Уровень параллелизма этого пула равен Runtime.getRuntime().availableProcessors() - 1.
Пример:
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
System.out.println("Доступных процессоров: " + Runtime.getRuntime().availableProcessors());
numbers.parallelStream()
.forEach(i -> System.out.println(Thread.currentThread().getName()));
// Вывод будет содержать имена потоков вида 'ForkJoinPool.commonPool-worker-N'
Как управлять количеством потоков?
По умолчанию изменить нельзя, но можно запустить параллельный стрим внутри своего экземпляра ForkJoinPool:
ForkJoinPool customPool = new ForkJoinPool(4); // Пул с 4 потоками
customPool.submit(() ->
list.parallelStream() // Теперь стрим использует customPool, а не commonPool
.forEach(...)
).join();
Важно: Это глобальная настройка для common pool. Изменять ее для всего приложения через системное свойство java.util.concurrent.ForkJoinPool.common.parallelism не рекомендуется без веских причин.
Ответ 18+ 🔞
Ну слушай, вот есть у тебя этот самый parallelStream(), красавец, такой удобный. А он, сука, работает на общем пуле потоков, на этом ForkJoinPool.commonPool. И знаешь, сколько у него там народу? Ну, по дефолту — сколько у тебя ядер процессора минус один. Runtime.getRuntime().availableProcessors() - 1. Вот такая магия, блядь.
Смотри, как это выглядит в коде, чтоб совсем понятно было:
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
System.out.println("Доступных процессоров: " + Runtime.getRuntime().availableProcessors());
numbers.parallelStream()
.forEach(i -> System.out.println(Thread.currentThread().getName()));
// Вывод будет содержать имена потоков вида 'ForkJoinPool.commonPool-worker-N'
Запустишь — и увидишь, как эти ForkJoinPool.commonPool-worker-1 и прочие суетятся, работу твою делают. Всё вроде красиво.
Но вот, допустим, тебе мало этих потоков. Или, наоборот, много — овердохуища, и ты хочешь их придушить. Как быть-то? Ну, глобально-то менять настройки общего пула через java.util.concurrent.ForkJoinPool.common.parallelism — это, блядь, как из пушки по воробьям. Не рекомендую, если только ты не уверен, что весь твой код от этого не накроется медным тазом.
А вот локально — пожалуйста, делай что хочешь! Загони свой параллельный стрим в свой собственный ForkJoinPool. Вот так:
ForkJoinPool customPool = new ForkJoinPool(4); // Пул с 4 потоками
customPool.submit(() ->
list.parallelStream() // Теперь стрим использует customPool, а не commonPool
.forEach(...)
).join();
Вот и всё, ёпта! Теперь твой стрим будет юзать твой пул с четырьмя работягами, а не общак. Главное — не забудь потом за собой прибраться, join() там вызвать или как-то иначе завершить работу, а то потоки так и останутся висеть, как манда с ушами.
Короче, инструмент мощный, но, как и всё в этих ваших итернетах, требует мозгов. А то так и до OutOfMemoryError недалеко, если бездумно плодить пулы. Думай, бошка, думай!