it-swarm.com.ru

Как обеспечить порядок обработки в потоках Java8?

Я хочу обработать списки внутри объекта XML Java. Я должен обеспечить обработку всех элементов в порядке их получения.

Должен ли я поэтому вызывать sequential для каждого stream, который я использую? list.stream().sequential().filter().forEach()

Или достаточно просто использовать поток, если я не использую параллелизм? list.stream().filter().forEach()

116
membersound

Вы задаете неправильный вопрос. Вы спрашиваете о sequential против parallel, тогда как вы хотите обрабатывать элементы по порядку , поэтому вы должны спросить о упорядоченность . Если у вас есть упорядоченный поток и вы выполняете операции, которые гарантируют поддержание порядка, не имеет значения, обрабатывается ли поток параллельно или последовательно; Реализация будет поддерживать порядок.

Упорядоченное свойство отличается от параллельного и последовательного. Например. если вы вызываете 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());

вся операция может выиграть от параллельного выполнения, но результирующий список всегда будет в правильном порядке, независимо от того, используете ли вы параллельный или последовательный поток.

285
Holger