Quels sont les avantages d'utiliser un ExecutorService?
Quel est l'avantage d'utiliser ExecutorService
au-dessus des fils courants passant un Runnable
dans le constructeur Thread
?
8 réponses
ExecutorService
résume bon nombre des complexités associées aux abstractions de niveau inférieur comme le Thread
brut . Il fournit des mécanismes pour démarrer, fermer, soumettre, exécuter et bloquer en toute sécurité sur la fin réussie ou abrupte des tâches (exprimé comme Runnable
ou Callable
).
à Partir de JCiP , Section 6.2, directement de la bouche des chevaux:
Executor
peut être un interface simple, mais elle forme la base d'un cadre souple et puissant pour l'exécution asynchrone des tâches qui soutient une grande variété de politiques d'exécution des tâches. Il fournit un moyen standard de découplage task submission de task execution , décrivant les tâches commeRunnable
. Les implémentationsExecutor
fournissent également un support du cycle de vie et des hooks pour ajouter la collecte de statistiques, la gestion d'applications et la surveillance. ... L'utilisation d'unExecutor
est habituellement la façon la plus facile de mettre en œuvre un dessin ou modèle producteur-consommateur dans votre application.
plutôt que de passer votre temps à mettre en œuvre (souvent incorrectement, et avec beaucoup d'efforts) l'infrastructure sous-jacente du parallélisme, le cadre j.u.concurrent
vous permet de vous concentrer sur la structuration des tâches, des dépendances, du parallélisme potentiel. Pour une grande parcelle de demandes concurrentes, il est simple de identifiez et exploitez les limites des tâches et utilisez j.u.c
, vous permettant de vous concentrer sur le sous-ensemble beaucoup plus petit de véritables défis de concurrence qui peuvent nécessiter des solutions plus spécialisées.
en outre, malgré l'apparence boilerplate, la page de L'API Oracle résumant les utilitaires de concurrence comprend des arguments vraiment solides pour les utiliser, notamment:
développeurs sont susceptibles de déjà comprendre la bibliothèque standard les cours, donc il n'y a pas besoin d'apprendre L'API et le comportement de ad-hoc composants concurrents. Outre, les applications concurrentes sont loin plus simple à déboguer quand ils sont construits sur fiable, bien des composants testés.
Ce question DONC , demande un bon livre, dont la réponse immédiate est JCiP. Si vous ne l'avez pas déjà fait, procurez-vous une copie. L'approche globale de la la concurrence présentée ici va bien au-delà de cette question, et vous sauvera beaucoup de chagrin à long terme.
un avantage que je vois est dans la gestion/programmation de plusieurs threads. Avec ExecutorService, vous n'avez pas à écrire votre propre gestionnaire de threads qui peut être harcelé par des bogues. Ceci 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 vous voulez que cette opération s'exécute en plusieurs threads à la fois afin d'améliorer les performances de votre programme. Ce n'est qu'un exemple, il y a encore de nombreux cas où vous voulez programmer ou exécuter plusieurs threads et utiliser ExecutorService comme votre gestionnaire de threads.
pour exécuter un seul thread, Je ne vois aucun avantage évident à utiliser ExecutorService.
ci-dessous sont quelques avantages:
- Exécuteur testamentaire service à gérer thread de manière asynchrone
- utilisez callable pour obtenir le résultat de retour après l'achèvement du thread.
- Gérer l'attribution du travail au filetage libre et la revente du travail terminé à partir du filetage pour attribuer automatiquement un nouveau travail
- fork - join-cadre pour le traitement en parallèle
- meilleure communication entre les fils
- invokeAll et invokeAny donner plus de contrôle à exécuter tout ou thread à la fois
- l'arrêt de fournir des capacités pour l'achèvement de tous les threads de travail assigné
- Prévue Exécuteur des Services de fournir des méthodes pour la production de répéter les invocations de runnables et callables Espérons, vous aidera à
les limitations suivantes du Thread traditionnel surmontées par Executor framework(built-in Thread Pool framework).
- la Mauvaise Gestion des Ressources c'est à dire de tenir sur la création de nouvelles ressources pour chaque demande. Aucune limite à la création de ressources. En utilisant Executor framework, nous pouvons réutiliser les ressources existantes et limiter la création de ressources.
- pas robuste : si nous continuons à créer de nouveaux le fil nous aurons
StackOverflowException
exception par conséquent, à notre JVM en panne. - création de temps : pour chaque demande, nous devons créer de nouvelles ressources. La création de nouvelles ressources prend du temps. c'est à dire de Threads Création d' > tâche. En utilisant Executor framework nous pouvons être construits dans Thread Pool.
avantages du pool de fils
-
utilisation de fils Pool réduit le temps de réponse en évitant la création de thread pendant le traitement des requêtes ou des tâches.
-
L'utilisation de Thread Pool vous permet de modifier votre politique d'exécution comme vous le souhaitez. vous pouvez passer d'un thread simple à plusieurs threads en remplaçant simplement L'implémentation D'ExecutorService.
-
Thread Pool dans L'application Java augmente la stabilité du système en créant un nombre configuré de threads décidé sur la base du système charge et ressources disponibles.
-
Thread Pool libère le développeur d'applications des trucs de gestion de thread et permet de se concentrer sur la logique d'affaires.
est-ce vraiment si cher de créer un nouveau fil?
comme benchmark, je viens de créer 60 000 threads avec Runnable
s avec des méthodes vides run()
. Après avoir créé chaque thread, j'ai immédiatement appelé sa méthode start(..)
. Cela a pris environ 30 secondes d'intense activité CPU. Des expériences similaires ont été faites en réponse à cette question . Le résumé de ceux - ci est que si les fils ne finissent pas immédiatement, et une grande nombre de threads actifs s'accumulent (quelques milliers), puis 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 L'OS, mais pas nécessairement, il semble .
donc, autant que je puisse voir, si nous parlons de lancer disons 10 threads par seconde, et ils finissent tous plus vite que les nouveaux commencent, et nous pouvons garantir que ce taux ne sera pas dépassé trop, alors L'Exécutorservice n'offre aucun avantage concret en termes de performances visibles ou de stabilité. (Bien qu'il puisse encore être plus pratique ou plus lisible d'exprimer certaines idées de concurrence en code. D'un autre côté, si vous planifiez des centaines ou des milliers de tâches par seconde, qui prennent du temps à exécuter, vous pourriez 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 requêtes vers un serveur, et qu'il y a un pic dans le intensité des requêtes que votre serveur reçoit. Mais par exemple, un thread en réponse à chaque événement d'entrée utilisateur (touche press, mouvement de la souris) semble parfaitement correct, tant que les tâches sont brèves.
ExecutorService donne également accès à FutureTask qui retournera à la classe calling les résultats d'une tâche de fond une fois terminée. Dans le cas de la mise en œuvre appelable
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());
}
avant la version java 1.5, Thread / Runnable a été conçu pour deux services séparés
- Unité de travail
- exécution de cette unité de travail
ExecutorService dissocie ces deux services en désignant Exécutable/Appelable comme unité de travail et l'exécutant en tant que mécanisme d'exécution ( avec lifecycling) à l'unité de travail
la création d'un grand nombre de threads sans restriction au seuil maximum peut causer l'application de manquer de mémoire tas. A cause de cela, créer un ThreadPool est une bien meilleure solution. En utilisant ThreadPool nous pouvons limiter le nombre de threads qui peuvent être regroupés et réutilisés.
Exécuteurs cadre faciliter le processus de création de pools de Threads en java. La classe Executors fournit une implémentation simple D'ExecutorService en utilisant ThreadPoolExecutor.
Source: