Почему вызов метода Reduce в параллельном потоке с изменяемым объектом в качестве идентификатора не резервирует порядок в результате? - PullRequest
0 голосов
/ 10 ноября 2018

Существует следующий, казалось бы, "правильный" код:

List<String> list = Arrays.asList("1","2","3","4","5","6",
    "7","8","9","10","11","12");
String result = list.parallelStream()
   .reduce(new StringBuilder(), StringBuilder::append, 
       StringBuilder::append).toString();
System.out.println(result);

Проблема этого фрагмента в том, что identity , new StringBuilder() в вызове метода reduce изменяемый , таким образом, result является подбитым , то есть порядок result не сохраняется.Но я не могу полностью понять причину, поэтому я не могу представить себе случай производства result с в порядке, отличном от исходного list.Поэтому я нарисовал соответствующую карту-уменьшение диаграмму, которая случайно получила result с сохранением порядка: enter image description here

Вопрос: Во-первых,Я хотел бы подтвердить, что эта диаграмма верна.Во-вторых, если эта диаграмма верна, я хотел бы знать, где причина этого фрагмента кода, который не всегда создает result с сохранением порядка

1 Ответ

0 голосов
/ 10 ноября 2018

Ваша диаграмма неверна - вы предполагаете, что каждое параллельное сокращение начинается с нового StringBuilder. Вместо этого каждое параллельное сокращение начинается с того же элемента идентификации - с того же StringBuilder (тот, который вы создаете и передаете в качестве первого параметра методу reduce).

Каждый параллельный поток вызывает StringBuilder.append для (единственного и единственного) StringBuilder, который вы передаете методу reduce, тем самым добавляя к нему текущий элемент.

Следующим шагом является объединение частичных результатов, также путем вызова StringBuilder.append в том же StringBuilder, добавляя копии содержимого StringBuilder в себя.


Чтобы создать нарисованную диаграмму, вам нужно будет передать Supplier<StringBuilder> в качестве первого параметра операции уменьшения.

На самом деле, согласно комментарию Хольгера, это возможно при использовании Mutable Reduction .

Для этого вы вызываете не метод Reduce, а метод collect:

List<String> list = Arrays.asList("1","2","3","4","5","6",
    "7","8","9","10","11","12");
String result = list.parallelStream()
   .collect(StringBuilder::new, StringBuilder::append, 
       StringBuilder::append).toString();
System.out.println(result);
...