ThreadPool ne pas exécuter des tâches en séquence
Je suis en utilisant le Executor
cadre spécifiquement Executors.newCachedThreadPool();
J'ai une liste de Runnable
s par exemple 100.
Les 50 premiers créer chacun une valeur (stockés dans une liste) pour être utilisé par le dernier 50.
J'ai pensé que si je passe le Runnable
s dans le executor.execute()
dans l'ordre qu'ils sont dans la liste, ils seraient
également exécutées dans le même ordre.
Mais ce n'est pas le cas.
Les tâches semblent être exécutées dans un ordre aléatoire et ils sont entrelacés, pas exécutés dans l'ordre.
Est-ce la façon dont il est suppose de travailler? De toute façon de contourner ce problème?
Grâce
Les exécuteurs.execute() ne fait pas les garanties de classement. Les travailleurs vont prendre de la file d'attente dans l'ordre, mais peut-être le contexte de commutation à tout moment avant l'achèvement des travaux. Donc si vous avez 50 threads la liste peut sauter jusqu'à 50 tâches à venir.
L'ordre n'est garanti que si vous avez un thread. Sinon, le prochain thread va commencer la prochaine tâche.
L'ordre n'est garanti que si vous avez un thread. Sinon, le prochain thread va commencer la prochaine tâche.
OriginalL'auteur Cratylus | 2010-12-17
Vous devez vous connecter pour publier un commentaire.
Vous avez besoin de présenter les travaux en deux lots, ou créez autrement un explicite "passe-avant" de la relation. Suggérer à la construction de deux lots de travaux et à l'aide de
invokeAll(batch1); invokeAll(batch2);
LainvokeAll()
méthode va exécuter toutes les tâches et bloc jusqu'à la fin. Vous pouvez avoir besoin pour envelopper votreRunnable
s commeCallable
s, que vous pouvez faire avecExecutors.callable(Runnable r)
. (@Cameron Skinner me battre pour obtenir quelques exemple de code, voir la réponse pour en savoir plus...)Le point de l'ensemble des interprètes est d'abstraire les détails de l'exécution, de sorte que la commande n'est pas garantie, sauf si explicitement indiqué. Si vous voulez strictement séquentielle d'exécution, de le faire dans le fil que vous êtes en cours d'exécution dans (la plus simple), de le faire dans un seul thread d'exécuteur testamentaire, d'ala
Executors.newSingleThreadExecutor()
, ou explicitement synchroniser les tâches. Si vous souhaitez faire le dernier, vous pouvez utiliser une barrière ou d'un verrou et d'avoir les tâches dépendantes sur le bloc de la barrière/loquet. Vous pourriez également avoir le premier bloc de tâches de mettre en œuvreCallable
, retourFuture
, et ont les tâches dépendantes appelmyFuture.get()
qui les aurait fait bloc jusqu'à ce que les résultats sont retournés.Si vous en dire plus au sujet de vos applications, nous pourrions être en mesure d'aider plus précisément.
Eh bien, une barrière est probablement excessif pour cette tâche, mais, conceptuellement, si vous avez des lots de tâches qui représentent une unité de travail qui ont besoin de compléter ensemble avant un autre traitement peut démarrer à nouveau, vous pouvez utiliser un download.oracle.com/javase/6/docs/api/java/util/concurrent/... pour cet effet. C'est lourd dans votre cas, plus souvent utilisé lorsque vous avez beaucoup d'itérations, et vous n'avez batch1 -> batch2
OriginalL'auteur andersoj
C'est le bon comportement. Vous n'avez aucune garantie sur l'ordre de la Runnables sont exécutées.
Exécuteurs exécuter dans parallèle, alors qu'il semble que vous voulez les tâches s'exécutent dans série. Vous pouvez soumettre les 50 premiers emplois, attendre pour eux à la fin, puis soumettre le second de 50 emplois, ou (si l'ordre d'exécution est important) il suffit d'exécuter le tout dans un seul thread.
Par exemple,
invokeAll(tasks)
de soumettre chaque appelable à son tour? Est-il plus optimisé pour faireinvokeAll
?invokeAll
renvoie uniquement lorsque toutes les tâches sont terminées, donc vous n'avez pas besoin d'écrire du code pour l'attente.OriginalL'auteur Cameron Skinner
Vous pourriez peut-être
execute
la première 50,shutdown
etawaitTermination
, et alors seulementexecute
les autres 50? Voir cette réponse pour des exemples de code.Il n'y a pas de raison de jeter parfaitement bonnes exécuteur simplement de s'assurer que les tâches sont terminées...
invokeAll()
fait cela, ou vous pouvez gagner jusqu'Future
s et attendre pour eux de complet.Un exemple de code sur la façon d'utiliser
awaitTermination
est liée à partir de ma réponse. Cependant, andersoj la réponse sonne comme la bonne chose à faire.OriginalL'auteur Fabian Steeg