Por qué la secuencia paralela se recostack secuencialmente en Java 8

¿Por qué forEach imprime números en orden aleatorio, mientras que la collect siempre recoge los elementos en el orden original, incluso de la secuencia paralela?

 Integer[] intArray = {1, 2, 3, 4, 5, 6, 7, 8}; List listOfIntegers = new ArrayList(Arrays.asList(intArray)); System.out.println("Parallel Stream: "); listOfIntegers .stream() .parallel() .forEach(e -> System.out.print(e + " ")); System.out.println(); // Collectors List l = listOfIntegers .stream() .parallel() .collect(Collectors.toList()); System.out.println(l); 

Salida:

 Parallel Stream: 8 1 6 2 7 4 5 3 [1, 2, 3, 4, 5, 6, 7, 8] 

Hay dos tipos diferentes de “orden” que están sucediendo aquí, lo que hace que la discusión sea confusa.

Un tipo es el orden de encuentro , que se define en la documentación de secuencias . Una buena forma de pensar sobre esto es el orden espacial o de izquierda a derecha de los elementos en la colección fuente. Si la fuente es una List , considere que los elementos anteriores están a la izquierda de los elementos posteriores.

También hay procesamiento o orden temporal , que no está definido en la documentación, pero que es el orden de tiempo en el que los elementos son procesados ​​por diferentes hilos. Si los elementos de una lista se procesan en paralelo por diferentes subprocesos, un subproceso podría procesar el elemento situado más a la derecha en la lista antes del elemento situado más a la izquierda. Pero la próxima vez puede que no.

Incluso cuando los cálculos se realizan en paralelo, la mayoría de los Collectors y algunas operaciones de la terminal se organizan cuidadosamente para que conserven el orden de encuentro desde la fuente hasta el destino, independientemente del orden temporal en el que diferentes hilos puedan procesar cada elemento.

Tenga en cuenta que el forEach terminal forEach no preserva la orden de encuentro. En cambio, se ejecuta por cualquier hilo que ocurra para producir el siguiente resultado. Si quieres algo así como cada forEach que preserve el orden de encuentro, utiliza forEachOrdered en forEachOrdered lugar.

Consulte también las preguntas frecuentes sobre Lambda para obtener más información sobre cómo ordenar problemas.

El método Collectors.toList especifica que el Collector devuelto agrega elementos a la lista en orden de encuentro.

Devoluciones:

un colector que recoge todos los elementos de entrada en una lista, en orden de encuentro

No importa si Stream es paralelo; el orden se conserva.

Además, al observar el código fuente de los Collectors , el Collector devuelto llama a addAll en una ArrayList al fusionarse, y eso preserva el orden. Por ejemplo, si un hilo tiene {1, 2} y el siguiente hilo tiene {3, 4}, entonces la llamada a addAll produce {1, 2, 3, 4}. Además, el Collector devuelto no tiene la característica UNORDERED .