Ответ
По умолчанию ForkJoinPool создает количество потоков, равное количеству доступных процессоров (Runtime.getRuntime().availableProcessors()). Это значение определяет уровень параллелизма (parallelism) пула.
Пример:
ForkJoinPool commonPool = ForkJoinPool.commonPool();
System.out.println(commonPool.getParallelism()); // Выведет, например, 8 на 8-ядерном процессоре
Важные детали:
- Общий пул (commonPool): Используется по умолчанию для параллельных операций (например, в
CompletableFutureи параллельных стримах). Его уровень параллелизма равенколичество_ядер - 1. - Создание кастомного пула: Можно задать свое значение через конструктор.
ForkJoinPool customPool = new ForkJoinPool(16); // Пул с параллелизмом 16 - Принцип работы: Пул использует алгоритм work-stealing — простаивающие потоки "крадут" задачи из очередей занятых потоков, что повышает утилизацию ресурсов.
- Фактическое число потоков: Может быть меньше уровня параллелизма, если задачи не требуют такого количества, или временно больше для компенсации блокирующих операций.
Ответ 18+ 🔞
Так, слушай, про этот ваш ForkJoinPool... Ну, блядь, классика же! Он, сука, по умолчанию ведёт себя как умный, но жадный до ядер мужик.
Вот смотри, создаёшь ты его просто так, без параметров — он сразу лезет в систему и считает, сколько у тебя там этих ядер процессорных торчит. Runtime.getRuntime().availableProcessors(), всё такое. Это число он и берёт за основу, называет это «уровнем параллелизма». То есть если у тебя комп восьмиядерный, он и настрóится примерно на восемь рабочих потоков. Не больше, не меньше, чтоб ресурсы зря не жрать.
Вот, смотри, как это проверить:
ForkJoinPool commonPool = ForkJoinPool.commonPool();
System.out.println(commonPool.getParallelism()); // Выведет, например, 8 на 8-ядерном процессоре
А теперь, блядь, важный момент, который многих вводит в ступор! Есть у них там общий пул (commonPool). Эта, сука, штука используется везде, где только можно: в CompletableFuture, в параллельных стримах... И знаешь, какой у него подвох? Он берёт не все ядра, а количество_ядер - 1. То есть один поток он как бы оставляет «про запас», для других дел системы. Хитро, ёпта!
Но если тебе этот общий пул не нравится, как мартышлюшка какая-то, ты можешь создать свой, кастомный. С блэкджеком и параллелизмом побольше!
ForkJoinPool customPool = new ForkJoinPool(16); // Пул с параллелизмом 16
Вот тут уже твоя воля — хоть 100 потоков на одном ядре создавай, только потом не ори, что комп вентилятором взлетает.
А самое, блядь, красивое в нём — это принцип work-stealing. Представь: у каждого потока своя очередь задач. Один поток уже всё сделал, сидит, бздит. А другой загружен по уши. Так вот, первый не будет сидеть сложа руки — он подкрадётся и украдёт задачу из хвоста очереди занятого потока! Красота же, ебать мои старые костыли! Ресурсы не простаивают, все при деле.
И последнее, чтобы голова не лопнула: фактическое число потоков может плавать. Оно может быть и меньше заявленного параллелизма, если задач мало. А может и временно вырасти — например, если какая-то задача тупо заблокировалась и ждёт ввода-вывода. Пул это видит и создаёт дополнительные потоки, чтобы другие задачи не простаивали. Умная система, чёрт побери!