Я читал о безгражданстве и наткнулся на это в документе:
Результаты потокового конвейера могут быть недетерминированными или неправильными, если поведенческие параметры для операций потока являются состоящими. Лямбда с состоянием (или другой объект, реализующий соответствующий функциональный интерфейс) - это тот, чей результат зависит от любого состояния, которое может измениться во время выполнения потокового конвейера.
Теперь, если у меня есть список строк (скажем, strList
), а затем я пытаюсь удалить дублирующиеся строки из него, используя параллельные потоки, следующим образом:
List<String> resultOne = strList.parallelStream().distinct().collect(Collectors.toList());
или если мы хотим, чтобы регистр не учитывался:
List<String> result2 = strList.parallelStream().map(String::toLowerCase)
.distinct().collect(Collectors.toList());
Может ли этот код иметь какие-либо проблемы, так как параллельные потоки будут разделять входные данные и отличать их в одном фрагменте, не обязательно означать отличные во всем входном сигнале?
РЕДАКТИРОВАТЬ (Краткое резюме ответов ниже)
distinct
является операция с состоянием, и в случае промежуточных операций с состоянием параллельные потоки могут потребовать многократных проходов или существенных издержек буферизации. Также distinct
могут быть реализованы более эффективно, если упорядочение элементов не имеет значения. Также согласно документу:
Для упорядоченных потоков выбор отдельных элементов является стабильным (для дублированных элементов элемент, появляющийся первым в порядке встречи, сохраняется.) Для неупорядоченных потоков гарантии стабильности не предоставляются.
Но в случае, когда упорядоченный поток, работающий в параллельном режиме, различные могут быть нестабильными - это означает, что он будет содержать произвольный элемент в случае дубликатов и не обязательно первый, как ожидалось, из distinct
от других.
По ссылке:
Внутренне, операция Different() сохраняет Set, который содержит элементы, которые были замечены ранее, но он скрыт внутри операции, и мы не можем получить его из кода приложения.
Так что в случае параллельных потоков он, вероятно, будет использовать весь поток или может использовать CHM (например, ConcurrentHashMap.newKeySet()
). А для заказанных, скорее всего, он будет использовать LinkedHashSet
или аналогичный конструкт.