Comment attendre de tous les threads pour finir, à l'aide de ExecutorService?
J'ai besoin d'exécuter un certain nombre des tâches 4 à un moment, quelque chose comme ceci:
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
taskExecutor.execute(new MyTask());
}
//...wait for completion somehow
Comment puis-je obtenir informé une fois que tous d'entre eux sont complets? Pour l'instant je ne peux pas penser à quelque chose de mieux que de fixer certaines compteur de tâches et de diminuer à la fin de chaque tâche, puis moniteur dans une boucle infinie ce compteur à 0; ou obtenir une liste de contrats à Terme et dans une boucle infinie moniteur isDone pour tous. Quelles sont les meilleures solutions n'impliquant pas de boucle infinie?
Grâce.
Vous devez vous connecter pour publier un commentaire.
Essentiellement sur une
ExecutorService
vous appelezshutdown()
et puisawaitTermination()
:Long.MAX_VALUE, TimeUnit.NANOSECONDS
équivaut à ne pas avoir un délai d'attente.invokeAll()
proposé par sjlee?java.util.concurrent
paquet documentation en vertu de laTiming
section: À attendre "pour toujours", vous pouvez utiliser une valeur deLong.MAX_VALUE
Long.MAX_VALUE
est égal à 106,751 Jours ou 292 ans (TimeUnit.NANOSECONDS.toDays(Long.MAX_VALUE);
), qui devrait être suffisant, ou l'utilisation de certains des plus grands TimeUnits.Utiliser un CountDownLatch:
et à l'intérieur de votre tâche (joindre en try /finally)
shutdown
/awaitTermination
.CyclicBarrier
semble également être utile lorsque vous avez besoin pour exécuter les threads dans les groupes à la fois.Executor
s qui ne peuvent tout simplement pas être fermé parce qu'ils sont utilisés par d'autres.ExecutorService.invokeAll()
le fait pour vous.futures
sont retournés, les tâches n'ont pas été achevé. Ils peuvent compléter dans le futur, et vous aurez un lien vers le résultat. C'est pourquoi il est appelé unFuture
. Vous avez la méthode Avenir.get(), qui va attendre la fin de la tâche pour obtenir un résultat.Vous pouvez utiliser des Listes de contrats à Terme, ainsi:
puis, quand vous voulez vous joindre à eux tous, de ses essentiellement l'équivalent de rejoindre à chaque, (avec l'avantage supplémentaire qu'il re-soulève des exceptions de threads à la main):
Fondamentalement, l'astuce est d'appeler .get() sur chaque Futur, un à un, au lieu de l'infini en boucle appel isDone() sur (toutes ou chacune). Ainsi, vous êtes assuré de "passer" à travers et passé ce bloc dès que le dernier thread se termine. Le problème, c'est que depuis le .get() appel de re-soulève des exceptions, si l'un des fils meurt, vous relèverait d'-ce peut-être avant les autres threads ont fini à l'achèvement [pour éviter cela, vous pouvez ajouter un
catch ExecutionException
autour de l'obtenir de l'appel]. L'autre inconvénient est qu'elle garde une référence pour tous les threads donc, si ils ont thread variables locales qu'ils ne seront pas recueillis jusqu'à après que vous avez passé ce bloc (bien que vous pourriez être en mesure de contourner ce problème, si il est devenu un problème, en supprimant l'Avenir est sur la liste de tableaux). Si vous voulais savoir qui d'Avenir "qui termine en premier", vous pouvez utiliser quelque chose comme https://stackoverflow.com/a/31885029/32453ExecutorCompletionService.take
: stackoverflow.com/a/11872604/199364Dans Java8 vous pouvez le faire avec CompletableFuture:
ExecutorService es = Executors.newFixedThreadPool(4); List< Future<?>> futures = new ArrayList<>(); for(Runnable task : taskList) { futures.add(es.submit(task)); } for(Future<?> future : futures) { try { future.get(); }catch(Exception e){ // do logging and nothing else } }
Juste mes deux cents.
Pour surmonter la condition de
CountDownLatch
de connaître le nombre de tâches à l'avance, vous pourriez faire de la bonne vieille façon à l'aide d'un simpleSemaphore
.Dans votre tâche appelez simplement
s.release()
comme vous le feriezlatch.countDown();
release
appelle arrive avant leacquire
appel, mais après la lecture du Sémaphore de la documentation, je vois que est bien.Un peu en retard pour le jeu mais pour l'amour de réalisation,...
Au lieu de "d'attente" pour toutes les tâches de finition, vous pouvez penser en termes d'Hollywood principe, "ne m'appelez pas, je vous appellerai" - quand je suis fini.
Je pense que le code résultant est plus élégant...
Goyave offre des outils intéressants pour accomplir cette tâche.
Un exemple ::
Envelopper un ExecutorService dans un ListeningExecutorService ::
Présenter une collection de callables pour l'exécution ::
Maintenant l'essentiel:
Joindre un rappel à la ListenableFuture, que vous pouvez utiliser pour être averti lorsque tous les contrats à terme complet ::
Cela offre également l'avantage que vous pouvez recueillir tous les résultats en un seul lieu une fois que le traitement est terminé...
Plus d'informations ici
runOnUiThread()
dansonSuccess()
.La CyclicBarrier classe en Java 5 et, plus tard, est conçu pour ce genre de chose.
Suivre l'un de ci-dessous approches.
submit
surExecutorService
et de vérifier le statut à l'appel de blocageget()
surFuture
objet comme suggéré parKiran
invokeAll()
sur ExecutorServiceshutdown, awaitTermination, shutdownNow
Api de ThreadPoolExecutor dans le bon ordreLiées SE questions:
Comment est CountDownLatch Java Multithreading?
Comment correctement l'arrêt java ExecutorService
Vous pouvez rassembler vos tâches dans un autre exécutable, qui envoie des notifications:
completed
compteur. Ainsi, après le départ de tous, à chaque notification, pourrait déterminer si le tous tâches accomplies. Notez qu'il est indispensable d'utiliser destry/finally
ainsi qu'un fini de notification (ou un autre notification danscatch
bloc) est donnée, même si une tâche échoue. Sinon, attendre pour toujours.voici deux options , il suffit de peu confondre ce qui est le mieux à faire.
Option 1:
Option 2:
Ici de mettre l'avenir.get(); dans le try catch est une bonne idée de droite?
Je viens d'écrire un exemple de programme qui permet de résoudre votre problème. Il n'y a pas de concise de mise en œuvre de donnée, donc je vais en ajouter un. Alors que vous pouvez utiliser
executor.shutdown()
etexecutor.awaitTermination()
, c'est pas la meilleure pratique que le temps pris par les différents threads sont imprévisibles.Juste pour donner plus de solutions différentes pour l'utilisation de verrouillage/obstacles.
Vous pouvez également obtenir les résultats partiels jusqu'à ce que tous finir à l'aide d' CompletionService.
De Java de la Simultanéité dans la pratique:
"Si vous avez un lot de calculs à se soumettre à un Exécuteur testamentaire, et vous souhaitez récupérer leurs résultats comme ils deviennent
disponible, vous pourriez retenir les Futurs associés à chaque tâche et à plusieurs reprises sondage pour la réalisation de l'appel de get avec un
délai d'attente de zéro. C'est possible, mais fastidieux. Heureusement, il existe une meilleure façon: fin de service."
Ici la mise en œuvre
Vous pouvez utiliser ce code:
C'est ma solution, basée dans "AdamSkywalker" conseil, et il fonctionne
Vous pouvez utiliser votre propre sous-classe de ExecutorCompletionService pour envelopper
taskExecutor
, et votre propre mise en œuvre de BlockingQueue d'être informé quand chaque tâche est terminée et effectuer le rappel ou de toute autre action que vous désirez lorsque le nombre de tâches accomplies atteint votre but désiré.vous devez utiliser
executorService.shutdown()
etexecutorService.awaitTermination
méthode.Un exemple comme suit :
Java 8 - On peut utiliser le volet de l'API de flux de processus. Veuillez voir extrait ci-dessous
Donc je poste ma réponse de lié question ici, au cas où quelqu'un voudrait-il un moyen plus simple de faire ce
J'ai créé le suivant: exemple de travail. L'idée est d'avoir un moyen de traiter d'un pool de tâches (je suis en utilisant une file d'attente à titre d'exemple) avec de nombreux Fils (déterminé par le programme de l'numberOfTasks/seuil), et attendre jusqu'à ce que toutes les discussions sont en cours pour continuer avec d'autres traitements.
Espère que cela aide!
Si
doSomething()
de jeter quelques autres exceptions, lalatch.countDown()
semble ne s'exécute pas, alors, que dois-je faire?Cela peut aider
On pourrait appeler waitTillDone() sur ce Coureur classe:
Vous pouvez réutilisation cette classe et appel waitTillDone() autant de fois que vous le souhaitez avant d'appeler de l'arrêt(), plus votre code est extrêmement simple. Aussi, vous n'ont pas à savoir la nombre de tâches à l'avance.
Pour l'utiliser, il suffit d'ajouter cette gradle/maven
compile 'com.github.matejtymes:javafixes:1.1.1'
dépendance à votre projet.Plus de détails peuvent être trouvés ici:
https://github.com/MatejTymes/JavaFixes
http://matejtymes.blogspot.com/2016/04/executor-that-notifies-you-when-task.html
Il y a une méthode dans exécuteur
getActiveCount()
- qui donne le nombre de threads actifs.Après couvrant le fil, nous pouvons vérifier si le
activeCount()
valeur est0
. Une fois que la valeur est zéro, cela signifie qu'il n'existe pas de threads actifs actuellement en cours d'exécution qui signifie que la tâche est terminée: