Скільки потоків породжується паралельним потоком у Java 8?


83

У JDK8, скільки потоків породжується, коли я використовую паралельний потік? Наприклад, у коді:

list.parallelStream().forEach(/** Do Something */);

Якщо цей список містить 100000 елементів, скільки потоків буде породжено?

Крім того, чи отримує кожна з ниток однакову кількість предметів для роботи, чи вона виділяється випадковим чином?



@assylias Дійсно хороша відповідь.
Умберто Раймонді

Відповіді:


79

Реалізація Oracle [1] паралельного потоку використовує поточний потік, а крім цього, за потреби, також і потоки, що складають пул приєднання форків ForkJoinPool.commonPool()за замовчуванням, розмір якого за замовчуванням дорівнює одному, меншому за кількість ядер вашого процесора .

Розмір загального пулу за замовчуванням можна змінити за допомогою цієї властивості:

-Djava.util.concurrent.ForkJoinPool.common.parallelism=8

Крім того, ви можете використовувати власний пул:

ForkJoinPool myPool = new ForkJoinPool(8);
myPool.submit(() ->
    list.parallelStream().forEach(/* Do Something */);
).get();

Що стосується замовлення, завдання будуть виконуватися, як тільки буде доступний потік, без певного порядку.

Як правильно зазначив @Holger, це деталь, що стосується реалізації (лише з одним нечітким посиланням внизу документа), обидва підходи працюватимуть на JVM Oracle, але точно не гарантовано працюватимуть на JVM від інших постачальників, властивість може не існують у реалізації, яка не входить до складу Oracle, і Streams не може навіть використовувати ForkJoinPoolвнутрішній візуалізаційний варіант, заснований на поведінці ForkJoinTask.forkабсолютно марних ( див. тут для деталей про це).


5
Можливо, варто додати, що якщо кількість завдань досить мала, паралельний потік може насправді працювати в основному потоці.
assylias

15
Слід зазначити, що використання StreamAPI ForkJoinPool- це деталь реалізації. Таким чином, обидва рішення працюють із поточною реалізацією Oracle, але не гарантовано, що вони будуть працювати всюди.
Holger

4

Хоча @uraimo правильний, відповідь залежить від того, що саме робить "Щось зробити". API parallel.streams використовує клас CountCompleter, який має кілька цікавих проблем. Оскільки фреймворк F / J не використовує окремий об'єкт для утримання результатів, довгі ланцюги можуть призвести до OOME. Крім того, ці довгі ланцюги іноді можуть спричинити переповнення стека. Відповідь на ці проблеми полягає у використанні техніки Паравентіал, на що я вказував у цій статті.

Іншою проблемою є надмірне створення потоку при використанні вкладеного паралельного forEach.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.