Ответ 1
Вы задаете неправильный вопрос. Вы спрашиваете о sequential
vs. parallel
, тогда как вы хотите обрабатывать элементы по порядку, поэтому вам нужно спросить о заказе. Если у вас есть упорядоченный поток и выполняются операции, которые гарантируют поддержание порядка, не имеет значения, обрабатывается ли поток параллельно или последовательно; реализация будет поддерживать порядок.
Упорядоченное свойство отличается от параллельного vs последовательного. Например. если вы вызываете stream()
в HashSet
, поток будет неупорядоченным, а вызов stream()
в List
возвращает упорядоченный поток. Обратите внимание, что вы можете вызвать unordered()
, чтобы освободить контракт на заказ и потенциально увеличить производительность. Как только поток не имеет порядка, нет способа восстановить заказ. (Единственный способ превратить неупорядоченный поток в упорядоченный - вызвать sorted
, однако полученный результат не обязательно является первоначальным порядком).
См. также раздел "Заказ" пакета java.util.stream
документация.
Чтобы обеспечить поддержание порядка заказа в течение всей операции потока, вам необходимо изучить документацию источника потоков, все промежуточные операции и операцию терминала для того, поддерживают ли они порядок или нет (или источник имеет порядок в первую очередь).
Это может быть очень тонким, например. Stream.iterate(T,UnaryOperator)
создает упорядоченный поток, а Stream.generate(Supplier)
создает неупорядоченный поток. Обратите внимание, что вы также сделали распространенную ошибку в своем вопросе, поскольку forEach
не поддерживает порядок. Вы должны использовать forEachOrdered
, если хотите обработать элементы потоков в гарантированном порядке.
Итак, если ваш List
в вашем вопросе действительно является java.util.List
, его метод stream()
вернет упорядоченный поток, а filter
не изменит порядок. Поэтому, если вы вызываете list.stream().filter() .forEachOrdered()
, все элементы будут обрабатываться последовательно по порядку, тогда как для list.parallelStream().filter().forEachOrdered()
элементы могут обрабатываться параллельно (например, фильтром), но действие терминала будет по-прежнему вызываться по порядку (что, очевидно, уменьшит преимущество параллельного выполнения).
Если вы, например, используете операцию типа
List<…> result=inputList.parallelStream().map(…).filter(…).collect(Collectors.toList());
вся операция может выиграть от параллельного выполнения, но полученный список всегда будет в правильном порядке, независимо от того, используете ли вы параллельный или последовательный поток.