web-dev-qa-db-fra.com

Quels sont les avantages de l'utilisation d'un ExecutorService?

Quel est l'avantage d'utiliser ExecutorService sur les threads en cours d'exécution en passant un Runnable dans le constructeur Thread?

44
devnull

ExecutorService résume un grand nombre des complexités associées aux abstractions de niveau inférieur comme le brut Thread. Il fournit des mécanismes pour démarrer, fermer, soumettre, exécuter et bloquer en toute sécurité la fin réussie ou brusque des tâches (exprimée en Runnable ou Callable).

De JCiP , section 6.2, directement de la bouche du cheval:

Executor peut être une interface simple, mais elle constitue la base d'un cadre flexible et puissant pour l'exécution de tâches asynchrones qui prend en charge une grande variété de politiques d'exécution de tâches. Il fournit un moyen standard de découplage soumission de tâche de exécution de tâche, décrivant les tâches comme Runnable. Les implémentations Executor fournissent également une prise en charge du cycle de vie et des crochets pour ajouter la collecte de statistiques, la gestion des applications et la surveillance. ... L'utilisation d'un Executor est généralement le chemin le plus simple pour implémenter une conception producteur-consommateur dans votre application.

Plutôt que de passer votre temps à mettre en œuvre (souvent de manière incorrecte et avec beaucoup d'efforts) l'infrastructure sous-jacente du parallélisme, le j.u.concurrent framework vous permet de vous concentrer sur les tâches de structuration, les dépendances, le parallélisme potentiel. Pour une large gamme d'applications simultanées, il est simple d'identifier et d'exploiter les limites des tâches et d'utiliser j.u.c, vous permettant de vous concentrer sur le sous-ensemble beaucoup plus petit des vrais défis de concurrence qui peut nécessiter des solutions plus spécialisées.

En outre, malgré l'apparence générale, la page API Oracle résumant les utilitaires de concurrence inclut des arguments vraiment solides pour les utiliser, notamment:

Les développeurs sont susceptibles de déjà comprendre les classes de bibliothèque standard, il n'est donc pas nécessaire d'apprendre l'API et le comportement des composants simultanés ad hoc. De plus, les applications simultanées sont beaucoup plus simples à déboguer lorsqu'elles sont basées sur des composants fiables et bien testés.

Cette question sur SO demande un bon livre, auquel la réponse immédiate est JCiP. Si ce n'est pas déjà fait, procurez-vous-en un exemplaire. L'approche globale de la concurrence présentée ici va bien au-delà de cette question, et vous fera économiser beaucoup de chagrin à long terme.

42
andersoj

Un avantage que je vois est dans la gestion/planification de plusieurs threads. Avec ExecutorService, vous n'avez pas à écrire votre propre gestionnaire de threads qui peut être en proie à des bugs. Cela est particulièrement utile si votre programme doit exécuter plusieurs threads à la fois. Par exemple, vous voulez exécuter deux threads à la fois, vous pouvez facilement le faire comme ceci:

ExecutorService exec = Executors.newFixedThreadPool(2);

exec.execute(new Runnable() {
  public void run() {
    System.out.println("Hello world");
  }
});

exec.shutdown();

L'exemple peut être trivial, mais essayez de penser que la ligne "hello world" consiste en une opération lourde et que vous souhaitez que cette opération s'exécute dans plusieurs threads à la fois afin d'améliorer les performances de votre programme. Ceci n'est qu'un exemple, il existe encore de nombreux cas où vous souhaitez planifier ou exécuter plusieurs threads et utiliser ExecutorService comme gestionnaire de threads.

Pour exécuter un seul thread, je ne vois aucun avantage clair à utiliser ExecutorService.

18
Manny

Les limitations suivantes du Thread traditionnel surmontées par le framework Executor (framework Thread Pool intégré).

  • Mauvaise gestion des ressources c'est-à-dire qu'il continue de créer de nouvelles ressources pour chaque demande. Aucune limite à la création de ressource. En utilisant le framework Executor, nous pouvons réutiliser les ressources existantes et limiter la création de ressources.
  • Pas robuste : Si nous continuons à créer un nouveau thread, nous aurons l'exception StackOverflowException, par conséquent notre JVM plantera.
  • Frais généraux Création de temps : Pour chaque demande, nous devons créer une nouvelle ressource. La création d'une nouvelle ressource prend du temps. c'est-à-dire création de threads> tâche. En utilisant le framework Executor, nous pouvons obtenir un pool de threads.

Avantages du pool de threads

  • L'utilisation du pool de threads réduit le temps de réponse en évitant la création de threads lors du traitement des demandes ou des tâches.

  • L'utilisation de Thread Pool vous permet de modifier votre politique d'exécution selon vos besoins. vous pouvez passer d'un seul thread à plusieurs threads en remplaçant simplement l'implémentation ExecutorService.

  • Thread Pool in Java augmente la stabilité du système en créant un nombre configuré de threads décidé en fonction de la charge du système et des ressources disponibles.

  • Thread Pool libère le développeur d'applications de la gestion des threads et permet de se concentrer sur la logique métier.

Source

10
Premraj

Voici quelques avantages:

  1. Le service exécuteur gère le thread de manière asynchrone
  2. Utilisez callable pour obtenir le résultat de retour après l'achèvement du thread.
  3. Gérer l'allocation du travail au fil libre et revendre le travail terminé à partir du fil pour attribuer automatiquement le nouveau travail
  4. fork - framework de jointure pour le traitement parallèle
  5. Meilleure communication entre les threads
  6. invokeAll et invokeAny donnent plus de contrôle pour exécuter un ou tous les threads à la fois
  7. l'arrêt permet de terminer tous les travaux assignés au thread
  8. Les services d'exécuteur planifié fournissent des méthodes pour produire des appels répétitifs de runnables et callables J'espère que cela vous aidera
7
Nitin

Est-ce vraiment si cher de créer un nouveau fil?

Comme référence, je viens de créer 60 000 threads avec des méthodes Runnables avec des méthodes run() vides. Après avoir créé chaque thread, j'ai appelé immédiatement sa méthode start(..). Cela a pris environ 30 secondes d'activité intense du processeur. Des expériences similaires ont été faites en réponse à cette question . Le résumé de ceux-ci est que si les threads ne se terminent pas immédiatement et qu'un grand nombre de threads actifs s'accumulent (quelques milliers), alors il y aura des problèmes: (1) chaque thread a une pile, donc vous manquerez de mémoire , (2) il pourrait y avoir une limite sur le nombre de threads par processus imposé par le système d'exploitation, mais pas nécessairement, il semble .

Donc, pour autant que je puisse voir, si nous parlons de lancer disons 10 threads par seconde, et ils se terminent tous plus vite que les nouveaux démarrent, et nous pouvons garantir que ce taux ne sera pas trop dépassé, alors l'ExecutorService n'offre aucun avantage concret en termes de performances ou de stabilité visibles. (Bien qu'il puisse toujours être plus pratique ou lisible d'exprimer certaines idées de concurrence dans le code.) D'un autre côté, si vous planifiez des centaines ou des milliers de tâches par seconde, ce qui prend du temps à s'exécuter, vous pouvez rencontrer de gros problèmes tout de suite. Cela peut se produire de manière inattendue, par exemple si vous créez des threads en réponse à des demandes adressées à un serveur, et que l'intensité des demandes reçues par votre serveur augmente. Mais par exemple un thread en réponse à chaque événement d'entrée utilisateur (appui sur une touche, mouvement de la souris) semble parfaitement bien, tant que les tâches sont brèves.

2
Evgeni Sergeev

ExecutorService donne également accès à FutureTask qui retournera à la classe appelante les résultats d'une tâche en arrière-plan une fois terminée. Dans le cas de la mise en œuvre de Callable

public class TaskOne implements Callable<String> {

@Override
public String call() throws Exception {
    String message = "Task One here. . .";
    return message;
    }
}

public class TaskTwo implements Callable<String> {

@Override
public String call() throws Exception {
    String message = "Task Two here . . . ";
    return message;
    }
}

// from the calling class

ExecutorService service = Executors.newFixedThreadPool(2);
    // set of Callable types
    Set<Callable<String>>callables = new HashSet<Callable<String>>();
    // add tasks to Set
    callables.add(new TaskOne());
    callables.add(new TaskTwo());
    // list of Future<String> types stores the result of invokeAll()
    List<Future<String>>futures = service.invokeAll(callables);
    // iterate through the list and print results from get();
    for(Future<String>future : futures) {
        System.out.println(future.get());
    }
1
Bade

La création d'un grand nombre de threads sans restriction au seuil maximal peut entraîner le manque d'application de la mémoire du tas. À cause de cela, la création d'un ThreadPool est une bien meilleure solution. En utilisant ThreadPool, nous pouvons limiter le nombre de threads pouvant être regroupés et réutilisés.

La structure des exécuteurs facilite le processus de création de pools de threads en Java. La classe Executors fournit une implémentation simple d'ExecutorService à l'aide de ThreadPoolExecutor.

Source:

Qu'est-ce que le cadre des exécuteurs

0
Virtual

Avant Java 1.5 version, Thread/Runnable était conçu pour deux services distincts

  1. Unité de travail
  2. Exécution de cette unité d'oeuvre

ExecutorService dissocie ces deux services en désignant Runnable/Callable comme unité de travail et Executor comme mécanisme pour exécuter (avec cycle de vie) l'unité de travail

0
Anil Saha