Pools de threads personnalisés dans les flux parallèles Java 8

Pools de threads personnalisés dans les flux parallèles Java 8

1. Vue d'ensemble

Java 8 a introduit le concept de Streams comme un moyen efficace d'effectuer des opérations en masse sur des données. Et lesStreams parallèles peuvent être obtenus dans des environnements qui prennent en charge la concurrence.

Ces flux peuvent être associés à des performances améliorées, au détriment de la surcharge multi-threading.

Dans ce rapide didacticiel, nous examineronsone of the biggest limitations of Stream API et verrons comment faire fonctionner un flux parallèle avec une instanceThreadPool personnalisée, ou -there’s a library that handles this.

2. ParallèleStream

Commençons par un exemple simple - appel de la méthodeparallelStream sur l’un des typesCollection - qui renverra éventuellement unStream parallèle:

@Test
public void givenList_whenCallingParallelStream_shouldBeParallelStream(){
    List aList = new ArrayList<>();
    Stream parallelStream = aList.parallelStream();

    assertTrue(parallelStream.isParallel());
}

Le traitement par défaut qui se produit dans un telStream utilise lesForkJoinPool.commonPool(),a Thread Pool shared by the entire application.

3. PersonnaliséThread Pool

Nous pouvons en fait passer unThreadPool personnalisé lors du traitement desstream.

L'exemple suivant permet à unStreamparallèle d'utiliser unThread Pool personnalisé pour calculer la somme des valeurs longues de 1 à 1000000, inclus:

@Test
public void giveRangeOfLongs_whenSummedInParallel_shouldBeEqualToExpectedTotal()
  throws InterruptedException, ExecutionException {

    long firstNum = 1;
    long lastNum = 1_000_000;

    List aList = LongStream.rangeClosed(firstNum, lastNum).boxed()
      .collect(Collectors.toList());

    ForkJoinPool customThreadPool = new ForkJoinPool(4);
    long actualTotal = customThreadPool.submit(
      () -> aList.parallelStream().reduce(0L, Long::sum)).get();

    assertEquals((lastNum + firstNum) * lastNum / 2, actualTotal);
}

Nous avons utilisé le constructeurForkJoinPool avec un niveau de parallélisme de 4. Certaines expériences sont nécessaires pour déterminer la valeur optimale pour différents environnements, mais une bonne règle consiste simplement à choisir le nombre en fonction du nombre de cœurs de votre processeur.

Ensuite, nous avons traité le contenu desStream parallèles, en les résumant dans l'appelreduce.

Cet exemple simple peut ne pas démontrer toute l'utilité de l'utilisation d'unThread Pool personnalisé, mais les avantages deviennent évidents dans les situations où nous ne voulons pas lier lesThread Pool communs à des tâches de longue durée (par ex. traitement des données à partir d'une source réseau), ou lesThread Pool communs sont utilisés par d'autres composants de l'application.

4. Conclusion

Nous avons brièvement examiné comment exécuter unStream parallèle en utilisant unThread Pool personnalisé. Dans le bon environnement et avec le bon usage du niveau de parallélisme, des gains de performance peuvent être obtenus dans certaines situations.

Les exemples de code complets référencés dans cet article peuvent être trouvésover on Github.