J'ai besoin d'exécuter un certain nombre de tâches 4 à la fois, quelque chose comme ceci:
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
taskExecutor.execute(new MyTask());
}
//...wait for completion somehow
Comment puis-je être averti une fois que tous sont terminés? Pour l'instant, je ne peux penser à rien de mieux que de définir un compteur de tâches global et de le diminuer à la fin de chaque tâche, puis de surveiller en boucle infinie ce compteur pour devenir 0; ou obtenez une liste de Futures et le moniteur de boucle infinie est fait pour chacun d'eux. Quelles sont les meilleures solutions n'impliquant pas de boucles infinies?
Merci.
Long.MAX_VALUE, TimeUnit.NANOSECONDS
équivalente à l'absence de délai d'expiration.java.util.concurrent
paquet dans la section: Pour attendre "indéfiniment", vous pouvez utiliser une valeur deTiming
Long.MAX_VALUE
Utilisez un CountDownLatch :
et au sein de votre tâche (joindre dans try / enfin)
la source
ExecutorService.invokeAll()
le fait pour vous.la source
futures
leur retour, les tâches ne sont pas terminées. Ils pourraient se terminer à l'avenir et vous aurez un lien vers le résultat. C'est pourquoi cela s'appelle unFuture
. Vous disposez de la méthode Future.get () , qui attend la fin de la tâche pour obtenir un résultat.Vous pouvez également utiliser Lists of Futures:
puis lorsque vous souhaitez vous joindre à chacun d'eux, c'est essentiellement l'équivalent de se joindre à chacun d'eux (avec l'avantage supplémentaire qu'il relance les exceptions des threads enfants au principal):
Fondamentalement, l'astuce consiste à appeler .get () sur chaque Future un à la fois, au lieu d'appeler en boucle infinie isDone () on (tous ou chacun). Vous êtes donc assuré de "passer" à travers et après ce bloc dès que le dernier thread se termine. La mise en garde est que, puisque l'appel .get () relance des exceptions, si l'un des threads meurt, vous le relancerez peut-être avant la fin des autres threads [pour éviter cela, vous pouvez ajouter un
catch ExecutionException
autour de l'appel get ]. L'autre mise en garde est qu'il conserve une référence à tous les threads, donc s'ils ont des variables locales de thread, ils ne seront collectés qu'après avoir passé ce bloc (bien que vous puissiez contourner ce problème, si cela devenait un problème, en supprimant L'avenir est hors de la liste des tableaux). Si vous vouliez savoir quel avenir "finit le premier"https://stackoverflow.com/a/31885029/32453la source
ExecutorCompletionService.take
: stackoverflow.com/a/11872604/199364En Java8, vous pouvez le faire avec CompletableFuture :
la source
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 l'exigence de
CountDownLatch
connaître le nombre de tâches à l'avance, vous pouvez le faire à l'ancienne en utilisant un simpleSemaphore
.Dans votre tâche, appelez
s.release()
comme vous le feriezlatch.countDown();
la source
release
appels se produisent avant l'acquire
appel, mais après avoir lu la documentation de Semaphore, je vois que ça va.Un peu tard pour le jeu mais pour finir ...
Au lieu d '«attendre» que toutes les tâches soient terminées, vous pouvez penser en termes du principe hollywoodien «ne m'appelez pas, je vous appellerai» - quand j'ai fini. Je pense que le code résultant est plus élégant ...
La goyave propose des outils intéressants pour y parvenir.
Un exemple ::
Enveloppez un ExecutorService dans un ListeningExecutorService ::
Soumettre une collection de callables pour exécution ::
Maintenant l'essentiel:
Attachez un rappel à ListenableFuture, que vous pouvez utiliser pour être averti lorsque tous les futurs se terminent:
Cela offre également l'avantage que vous pouvez collecter tous les résultats en un seul endroit une fois le traitement terminé ...
Plus d'informations ici
la source
runOnUiThread()
dansonSuccess()
.La classe CyclicBarrier dans Java 5 et versions ultérieures est conçue pour ce genre de chose.
la source
Suivez l'une des approches ci-dessous.
submit
dessusExecutorService
et vérifiez l'état en bloquant l'appelget()
sur l'Future
objet comme suggéré parKiran
invokeAll()
sur ExecutorServiceshutdown, awaitTermination, shutdownNow
API de ThreadPoolExecutor dans l'ordre appropriéQuestions SE connexes:
Comment CountDownLatch est-il utilisé dans le multithreading Java?
Comment arrêter correctement Java ExecutorService
la source
voici deux options, confondez un peu laquelle est la meilleure.
Option 1:
Option 2:
Ici, mettre future.get (); dans try catch est une bonne idée non?
la source
Vous pouvez envelopper vos tâches dans un autre exécutable, qui enverra des notifications:
la source
completed
compteur. Ainsi, après les avoir tous démarrés, à chaque notification, vous pourriez déterminer si toutes les tâches sont terminées. Notez qu'il est vital d'utilisertry/finally
pour qu'une notification terminée (ou une notification alternative encatch
bloc) soit donnée même si une tâche échoue. Sinon, j'attendrais pour toujours.Je viens d'écrire un exemple de programme qui résout votre problème. Aucune implémentation concise n'a été donnée, je vais donc en ajouter une. Bien que vous puissiez utiliser
executor.shutdown()
etexecutor.awaitTermination()
, ce n'est pas la meilleure pratique car le temps pris par différents threads serait imprévisible.la source
Juste pour fournir plus d'alternatives ici différentes pour utiliser les verrous / barrières. Vous pouvez également obtenir les résultats partiels jusqu'à ce qu'ils finissent tous d'utiliser CompletionService .
De Java Concurrency en pratique: "Si vous avez un lot de calculs à soumettre à un exécuteur et que vous souhaitez récupérer leurs résultats dès qu'ils sont disponibles, vous pouvez conserver le futur associé à chaque tâche et interroger à plusieurs reprises pour l'achèvement en appelant get avec un délai d'attente nul. C'est possible, mais fastidieux . Heureusement, il existe une meilleure solution : un service de finition. "
Ici l'implémentation
la source
Ceci est ma solution, basée sur l'astuce "AdamSkywalker", et ça marche
la source
Vous pouvez utiliser ce code:
la source
J'ai créé l'exemple de travail suivant. L'idée est d'avoir un moyen de traiter un pool de tâches (j'utilise une file d'attente comme exemple) avec de nombreux threads (déterminés par programme par numberOfTasks / threshold), et d'attendre que tous les threads soient terminés pour continuer avec un autre traitement.
J'espère que cela aide!
la source
Vous pouvez utiliser votre propre sous-classe d' ExecutorCompletionService pour envelopper
taskExecutor
, et votre propre implémentation de BlockingQueue pour être informé lorsque chaque tâche se termine et effectuer tout rappel ou toute autre action que vous souhaitez lorsque le nombre de tâches terminées atteint votre objectif souhaité.la source
vous devez utiliser
executorService.shutdown()
etexecutorService.awaitTermination
méthode.Un exemple comme suit:
la source
Donc, je poste ma réponse à partir d'une question liée ici, au cas où quelqu'un voudrait un moyen plus simple de le faire
la source
Java 8 - Nous pouvons utiliser l'API de flux pour traiter le flux. Veuillez consulter l'extrait ci-dessous
la source
Si vous
doSomething()
lancez d'autres exceptions, lelatch.countDown()
semble ne s'exécutera pas, alors que dois-je faire?la source
si vous utilisez plus de thread ExecutionServices SEQUENTIELLEMENT et que vous souhaitez attendre la fin de CHAQUE EXECUTIONSERVICE. La meilleure façon est comme ci-dessous;
la source
Cela pourrait aider
la source
Vous pouvez appeler waitTillDone () sur cette classe Runner :
Vous pouvez réutiliser cette classe et appeler waitTillDone () autant de fois que vous le souhaitez avant d'appeler shutdown (), et votre code est extrêmement simple . De plus, vous n'avez pas à connaître le nombre de tâches à l' avance.
Pour l'utiliser, ajoutez simplement cette
compile 'com.github.matejtymes:javafixes:1.3.1'
dépendance gradle / maven à votre projet.Plus de détails ici:
https://github.com/MatejTymes/JavaFixes
la source
Il existe une méthode dans l'exécuteur
getActiveCount()
- qui donne le nombre de threads actifs.Après avoir enjambé le fil, nous pouvons vérifier si la
activeCount()
valeur est0
. Une fois que la valeur est nulle, cela signifie qu'aucun thread actif n'est en cours d'exécution, ce qui signifie que la tâche est terminée:la source