Outre le fait que l'interface Executor
présente certains avantages par rapport aux threads simples (gestion, par exemple), existe-t-il une réelle différence interne (grande différence de performances, consommation de ressources ...) entre faire:
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(runnable);
Et:
Thread thread = new Thread(runnable);
thread.start();
Je ne demande qu'un seul fil ici.
Executors # newSingleThreadExecutor () crée ThreadPoolExecutor objet sous le capot,
voir le code ici: http://www.docjar.com/html/api/Java/util/concurrent/Executors.Java.html
133 public static ExecutorService newSingleThreadExecutor() {
134 return new FinalizableDelegatedExecutorService
135 (new ThreadPoolExecutor(1, 1,
136 0L, TimeUnit.MILLISECONDS,
137 new LinkedBlockingQueue<Runnable>()));
138 }
Le documentation de ThreadPoolExecutor explique dans quelles situations il offre des avantages:
Les pools de threads résolvent deux problèmes différents: ils fournissent généralement de meilleures performances lors de l'exécution d'un grand nombre de tâches asynchrones , en raison de la réduction de la charge d'appel par tâche, et ils fournissent un moyen de délimiter et de gérer les ressources, y compris les threads, consommées lors de l'exécution d'une collection de tâches. Chaque ThreadPoolExecutor conserve également des statistiques de base, telles que le nombre de tâches terminées.
Si tout ce dont vous avez besoin est d'exécuter un seul thread de temps en temps (disons une fois par heure), alors en termes de performances, l'utilisation de ThreadPoolExecutor
peut être plus lente, car vous devez instancier l'ensemble de la machine (pool + fil), puis jetez-le de la mémoire.
Mais si vous souhaitez utiliser ce thread unique souvent (disons toutes les 15 secondes), l'avantage est que vous ne créez le pool et le thread qu'une seule fois , en conservant en mémoire, et utilisez-le tout le temps pour gagner du temps en créant un nouveau fil de temps en temps (ce qui peut être assez cher, si vous voulez l'utiliser, disons toutes les 15 secondes environ).
C'est une abstraction et celles-ci ont toujours un "coût":
La principale différence est que le service vous permet de soumettre des tâches multiples, tandis que le thread peut exécuter exactement un Runnable. D'un autre côté, vous devez vous soucier de choses telles que "fermer" le service.
Une règle d'or: les aspects liés aux performances devraient être ici presque "ignorables". Pour cette raison, vous préférez la solution de service exécuteur "plus abstraite". Parce que cela vous permet de séparer vos préoccupations du filetage réel. Et plus important encore: si vous choisissez d'utiliser un type d'implémentation différent pour ce service ... le reste de votre code ne devrait pas avoir à s'en soucier.
Pour faire court: les abstractions coûtent, mais dans ce cas, vous préférez généralement la solution "plus abstraite". Parce qu'au final, cela réduit la complexité de votre solution.
La principale différence réside dans la politique d'exécution des tâches.
En créant une instance de Thread
ou en sous-classant Thread
, vous exécutez essentiellement une seule tâche.
En revanche, l'utilisation de Executors.newSingleThreadExecutor()
vous permet de soumettre plusieurs tâches. Étant donné que ces tâches sont garanties pas pour être exécutées simultanément, cela vous permet d'exploiter les avantages suivants confinement de thread :
Si vous n'avez qu'un Runnable
à exécuter, alors il y a pas de grande différence entre eux.
L'utilisation de thread simple peut être un peu plus efficace car la création d'un ExecutorService
tel que ThreadPoolExecutor
a autre chose à faire que de créer un nouveau thread. Par exemple, créer une file d'attente de blocage, créer une politique, bien que ces choses se fassent implicitement.
Et vous devez shutdown
l'exécuteur après l'exécution de ce runnable. Sinon, le thread unique de ce pool ne se fermera jamais.