web-dev-qa-db-fra.com

java 8 Stream () parallèle avec sorted ()

JDK 8 EA est maintenant disponible, et j'essaie juste de m'habituer au lambda et à la nouvelle API Stream. J'ai essayé de trier une liste avec un flux parallèle, mais le résultat est toujours faux:

import Java.util.ArrayList;
import Java.util.List;

public class Test
{
    public static void main(String[] args)
    {
        List<String> list = new ArrayList<>();
        list.add("C");
        list.add("H");
        list.add("A");
        list.add("A");
        list.add("B");
        list.add("F");
        list.add("");

        list.parallelStream() // in parallel, not just concurrently!
            .filter(s -> !s.isEmpty()) // remove empty strings
            .distinct() // remove duplicates
            .sorted() // sort them
            .forEach(s -> System.out.println(s)); // print each item
    }
}

SORTIE:

C
F
B
H
A

Notez que chaque fois que la sortie est différente. Ma question est, est-ce un bug? ou n'est-il pas possible de trier une liste en parallèle? si oui, alors pourquoi JavaDoc ne le dit pas? Dernière question, existe-t-il une autre opération dont la sortie serait différente selon le type de flux?

32
Eng.Fouad

Vous devez utiliser forEachOrdered, pas forEach.

Selon le document forEach:

Pour les pipelines de flux parallèles, cette opération ne garantit pas de respecter l'ordre de rencontre du flux, car cela sacrifierait l'avantage du parallélisme. Pour tout élément donné, l'action peut être effectuée à tout moment et dans le thread choisi par la bibliothèque. Si l'action accède à l'état partagé, elle est chargée de fournir la synchronisation requise.

52
Louis Wasserman

De plus, vous pouvez en savoir plus sur le parallélisme et forEachOrdered avec un très bel exemple de ici . En résumé, l'utilisation de forEachOrdered dans un flux parallèle peut entraîner la perte des avantages du parallélisme.

Voici l'exemple de la même ressource:

Integer[] intArray = {1, 2, 3, 4, 5, 6, 7, 8 };
List<Integer> listOfIntegers =
    new ArrayList<>(Arrays.asList(intArray));

System.out.println("listOfIntegers:");
listOfIntegers
    .stream()
    .forEach(e -> System.out.print(e + " "));
System.out.println("");

System.out.println("listOfIntegers sorted in reverse order:");
Comparator<Integer> normal = Integer::compare;
Comparator<Integer> reversed = normal.reversed(); 
Collections.sort(listOfIntegers, reversed);  
listOfIntegers
    .stream()
    .forEach(e -> System.out.print(e + " "));
System.out.println("");

System.out.println("Parallel stream");
listOfIntegers
    .parallelStream()
    .forEach(e -> System.out.print(e + " "));
System.out.println("");

System.out.println("Another parallel stream:");
listOfIntegers
    .parallelStream()
    .forEach(e -> System.out.print(e + " "));
System.out.println("");

System.out.println("With forEachOrdered:");
listOfIntegers
    .parallelStream()
    .forEachOrdered(e -> System.out.print(e + " "));
System.out.println("");

Et la sortie est

listOfIntegers:
1 2 3 4 5 6 7 8
listOfIntegers sorted in reverse order:
8 7 6 5 4 3 2 1
Parallel stream:
3 4 1 6 2 5 7 8
Another parallel stream:
6 3 1 5 7 8 4 2
With forEachOrdered:
8 7 6 5 4 3 2 1

Le cinquième pipeline utilise la méthode forEachOrdered, qui traite les éléments du flux dans l'ordre spécifié par sa source, que vous ayez exécuté le flux en série ou en parallèle. Notez que vous pouvez perdre les avantages du parallélisme si vous utilisez des opérations comme forEachOrdered avec des flux parallèles

.

6
cemal