Хотя в настоящее время существует множество отличных языков с полезными механизмами для обеспечения безопасного параллелизма, такими как каналы в Rust и Go, Java исторически имела надежную поддержку для включения параллелизма в ваш код. С течением времени механизмы, встроенные в язык для обеспечения безопасного параллелизма, расширились. Это ничем не отличается в Java 8 с потоками. Просто добавив узел обработки parallel()
как часть потока, мы можем заставить Java взять на себя тяжелую работу, и мы сможем написать наш поток как обычно (по крайней мере, так кажется), и Java будет обрабатывать необходимое разделение входных данных и объединение в конце. Увы, но у нас здесь нет бесплатного обеда. Мы не можем просто бросать параллельно
в наши потоки и ожидать, что все будет лучше.
Проблемы с потоками и параллельным программированием на самом деле не отличаются от параллельного программирования с использованием других инструментов на Java. Есть случаи, когда это может быть очень полезно, и могут быть места, где это вызовет новые проблемы с нулевой пользой. При этом существуют некоторые эвристики, которые можно использовать для определения того, в каких случаях параллельный поток может быть полезен. Например, потоки, которые создают бесконечные потоки с предельными
обрабатывающими узлами. Это может привести к сбою кода, поскольку код пытается понять, как правильно с ним обращаться. Еще одна вещь, которую следует иметь в виду, это то, что терминальная работа потока такова. Если это коллектор, то он не поддается распараллеливанию в такой степени, как, например, операция сокращения. Еще одна проблема параллельных потоков заключается в том, что по умолчанию они используют системный forkjoinpool по умолчанию. Даже если в ходе тестирования вы увидите хорошие улучшения при использовании параллельного потока, это может привести к ужасным результатам в производственной среде, где код может выполняться несколько раз параллельно. Что может случиться, так это то, что вся работа может встать в очередь в ожидании открытого потока, и в результате вы можете значительно снизить производительность. Хотя вы можете предоставить пул потоков только для определенной операции, в итоге вы получите несколько в основном неиспользуемых потоков.
Так что, похоже, мы сталкиваемся со многими проблемами при использовании параллельных потоков. Это действительно так, никто не говорил, что параллельное программирование будет простым. Итак, каковы некоторые варианты использования, в которых это может быть полезно. Как и во всех проблемах параллельной обработки, каждый поток должен выполнять достаточно большой объем работы. Например, у меня был хороший опыт использования параллельного потока до того, как в рамках моего потока были сделаны HTTP-запросы для получения дополнительной информации о данных. Это была очень сложная операция ввода-вывода, которая позволяла отправлять несколько запросов параллельно, что значительно ускоряло операцию. HTTP-запросы – это не единственный большой объем работы, который необходимо выполнить. Единственный способ узнать, выиграет ли ваш код от параллельного потока, – это попробовать его в разных средах.
На самом деле ключ к работе с параллельными потоками заключается в том, чтобы относиться к нему как к любому другому параллельному программированию. Протестируйте его, используйте только тогда, когда каждый поток выполняет значительный объем работы, и храните этот полезный инструмент в своем поясе инструментов.
Оригинал: “https://dev.to/kylec32/effective-java-use-caution-when-making-streams-parallel-18bo”