Я пытаюсь обработать код ниже, используя многопоточность на уровне заказа.
List<String> orders = Arrays.asList("order1", "order2",
"order3", "order4", "order1");
Текущее последовательное исполнение:
orders.stream().forEach(order -> {
rules.forEach(rule -> {
finalList.add(beanMapper.getBean(rule)
.applyRule(createTemplate.apply(getMetaData.apply(rule), command),
order));
});
});
Я пытался с помощью:
orders.parallelStream().forEach(order -> {}} // code snippet.
Но это меняет порядок rules.forEach (rule -> {}} .
Например:
Ввод:
List<String> orders = Arrays.asList("order1", "order2",
"order3", "order4", "order1");
List<String> rules = Arrays.asList("rule1", "rule2", "rule3");
Ожидаемый результат:
order1 with rule1, rule2, rule3
order2 with rule1, rule2, rule3
Фактический результат с parallelStream()
:
order1 with rule3, rule1, rule2
order1 with rule2, rule1, rule3
Меня не беспокоит порядок заказов , но меня беспокоит порядок правил . Заказы могут обрабатываться в любом порядке, но правила должны выполняться в том же порядке для каждого заказа.
Пожалуйста помоги.
java
multithreading
java-8
java-stream
Майянк Бишт
источник
источник
Вы добавляете элементы в
finalList
разные потоки одновременно. Это вызывает смешивание результатов применения правил к различным заказам (правила не группируются по их заказам).Вы можете исправить это, создав временный список для каждого,
order
а затем синхронно объединить все временные списки вfinalList
.Вот как вы можете сделать это с помощью Stream-API (Java 9+):
Примечание:
Collectors.flatMapping()
здесь используется вместо простогоflatMap
для синхронного запуска плоского отображения во время сбора потока.Аналог Java 8:
источник
beanMapper.getBean(rule) .applyRule(createTemplate.apply(getMetaData.apply(rule), command), order)
это не чистая функция, поэтому ее нельзя использовать параллельно. Попробуйте удалить все побочные эффекты от него;ConcurrentModificationException
трассировка стека может помочь найти их.Будет ли это работать?
Вывод
источник
Если это так, нет места для фактического параллелизма.
когда
а также
являются единственными действительными прогонами для 2 заказов и 2 правил,
и
считается недействительным, это не параллелизм, а просто рандомизация
order
s, предположительно без усиления. Если вам «надоело»order1
приходить первым, вы можете перетасовать список, но это все:Даже потоковая передача не нужна, просто две вложенные петли. Тест: https://ideone.com/qI3dqd
Оригинальный ответ
Нет. В
order
ы могут перекрывать друг друга, но порядокrule
с для каждого заказа сохраняются. Почему непараллельный долженforEach
делать что-то еще?Пример кода:
Тест: https://ideone.com/95Cybg
Пример вывода:
Порядок
order
s смешан, ноrule
s всегда 1-2-3. Я думаю, что ваш вывод просто скрыл пары (на самом деле вы не показали, как это было сгенерировано).Конечно, это может быть расширено с некоторыми задержками, поэтому обработка
order
s будет фактически перекрываться:Тест: https://ideone.com/cSFaqS
Пример вывода:
Это может быть что-то, что вы видели, просто без
orderx
части. Сorder
видимыми s можно отследить, чтоrule
s продолжают прибывать как 1-2-3, перorder
. Кроме того, ваш список примеров содержалorder1
дважды, что наверняка не помогло увидеть, что происходит.источник
order
s не может перекрываться (возможно, ониrule
с состоянием и существуют в ограниченном количестве копий, возможно, только в одной?). Но, как правило, нет параллелизма без параллельных вещей, в этом и заключается весь смысл параллелизма.Если вы не против попробовать стороннюю библиотеку. Вот пример с моей библиотекой: abacus-util
И вы даже можете указать номер потока:
Порядок
rule
будет сохранен.Кстати, поскольку он находится в параллельном потоке, фрагмент кода,
...finalList.add(...
скорее всего, не будет работать. Я думаю, что лучше собрать результат в список:это также выполнимо, даже если вы хотите сохранить порядок
order
по какой-то причине позже:источник