J'ai un objet avec une méthode nommée StartDownload()
, qui démarre trois threads.
Comment recevoir une notification lorsque chaque thread a fini de s'exécuter?
Existe-t-il un moyen de savoir si l'un (ou la totalité) du thread est terminé ou est toujours en cours d'exécution?
java
multithreading
Ricardo Felgueiras
la source
la source
Réponses:
Il existe plusieurs façons de procéder:
Comment mettre en œuvre l'idée n ° 5? Eh bien, une façon est de créer d'abord une interface:
puis créez la classe suivante:
puis chacun de vos threads s'étendra
NotifyingThread
et au lieu de l'implémenter,run()
il sera implémentédoRun()
. Ainsi, une fois terminés, ils avertiront automatiquement toute personne en attente de notification.Enfin, dans votre classe principale - celle qui démarre tous les Threads (ou au moins l'objet en attente de notification) - modifiez cette classe
implement ThreadCompleteListener
et immédiatement après la création de chaque Thread s'ajoute à la liste des écouteurs:puis, à la fin de chaque Thread, votre
notifyOfThreadComplete
méthode sera appelée avec l'instance Thread qui vient de se terminer (ou qui s'est plantée).Notez que mieux vaut
implements Runnable
plutôt queextends Thread
pourNotifyingThread
car l'extension de Thread est généralement déconseillée dans le nouveau code. Mais je codifie votre question. Si vous modifiez laNotifyingThread
classe à implémenter,Runnable
vous devez modifier une partie de votre code qui gère les threads, ce qui est assez simple à faire.la source
notify
méthode non pas dans l'indication de larun
méthode, mais après.Solution utilisant CyclicBarrier
label0 - la barrière cyclique est créée avec un nombre de parties égal au nombre de threads en cours d'exécution plus un pour le thread principal d'exécution (dans lequel startDownload () est en cours d'exécution)
label 1 - n-ième Téléchargement Le fil entre dans la salle d'attente
étiquette 3 - NUMBER_OF_DOWNLOADING_THREADS sont entrés dans la salle d'attente. Le fil principal de l'exécution les libère pour commencer à effectuer leurs tâches de téléchargement plus ou moins en même temps
étiquette 4 - le fil principal d'exécution entre dans la salle d'attente. C'est la partie du code la plus «délicate» à comprendre. Peu importe le fil qui entrera dans la salle d'attente pour la deuxième fois. Il est important que le thread entrant en dernier dans la salle s'assure que tous les autres threads de téléchargement ont terminé leurs tâches de téléchargement.
label 2 - n-ème DownloadingThread a terminé son travail de téléchargement et entre dans la salle d'attente. Si c'est le dernier, c'est-à-dire que NUMBER_OF_DOWNLOADING_THREADS y sont déjà entrés, y compris le thread principal d'exécution, le thread principal ne continuera son exécution que lorsque tous les autres threads auront terminé le téléchargement.
la source
Vous devriez vraiment préférer une solution qui utilise
java.util.concurrent
. Trouvez et lisez Josh Bloch et / ou Brian Goetz sur le sujet.Si vous n'utilisez pas
java.util.concurrent.*
et assumez la responsabilité d'utiliser directement Threads, vous devriez probablement l'utiliserjoin()
pour savoir quand un thread est terminé. Voici un mécanisme de rappel super simple. Commencez par étendre l'Runnable
interface pour avoir un rappel:Ensuite, créez un exécuteur qui exécutera votre exécutable et vous rappellera lorsque cela sera fait.
L'autre chose évidente à ajouter à votre
CallbackRunnable
interface est un moyen de gérer toutes les exceptions, alors peut-être y mettre unepublic void uncaughtException(Throwable e);
ligne et dans votre exécuteur, installer un Thread.UncaughtExceptionHandler pour vous envoyer à cette méthode d'interface.Mais faire tout cela commence vraiment à sentir
java.util.concurrent.Callable
. Vous devriez vraiment envisager d'utiliserjava.util.concurrent
si votre projet le permet.la source
runner.join()
sais pas trop ce que vous gagnez de ce mécanisme de rappel par rapport à un simple appel , puis au code que vous voulez après cela, puisque vous savez que le fil est terminé. Est-ce juste que vous définissez ce code comme une propriété de l'exécutable, de sorte que vous pourriez avoir des choses différentes pour différents exécutables?runner.join()
c'est le moyen le plus direct d'attendre. Je supposais que l'OP ne voulait pas bloquer leur fil d'appel principal car ils demandaient à être "notifiés" pour chaque téléchargement, ce qui pouvait se terminer dans n'importe quel ordre. Cela offrait un moyen d'être notifié de manière asynchrone.Voulez-vous attendre la fin? Si tel est le cas, utilisez la méthode Join.
Il existe également la propriété isAlive si vous souhaitez simplement la vérifier.
la source
Thread
àstart
, ce que fait le thread, mais l'appel revient immédiatement.isAlive
devrait être un simple test de drapeau, mais quand je l'ai googlé, la méthode étaitnative
.Vous pouvez interroger l'instance de thread avec getState () qui renvoie une instance de l'énumération Thread.State avec l'une des valeurs suivantes:
Cependant, je pense que ce serait une meilleure conception d'avoir un fil maître qui attend que les 3 enfants se terminent, le maître continuerait alors l'exécution lorsque les 3 autres auraient terminé.
la source
Vous pouvez également utiliser l'
Executors
objet pour créer un pool de threads ExecutorService . Ensuite, utilisez lainvokeAll
méthode pour exécuter chacun de vos threads et récupérer Futures. Cela bloquera jusqu'à ce que tous aient terminé l'exécution. Votre autre option serait d'exécuter chacun d'eux en utilisant le pool, puis d'appelerawaitTermination
pour bloquer jusqu'à ce que le pool ait fini de s'exécuter. Assurez-vous simplement d'appelershutdown
() lorsque vous avez terminé d'ajouter des tâches.la source
Beaucoup de choses ont changé ces 6 dernières années sur le front du multi-threading.
Au lieu d'utiliser
join()
et de verrouiller l'API, vous pouvez utiliser1. API ExecutorService
invokeAll()
2. CountDownLatch
3. ForkJoinPool ou
newWorkStealingPool()
dans Executors est une autre manière4.Itérer à travers toutes les
Future
tâches à partir de la soumissionExecutorService
et vérifier l'état avec blocage de l'appelget()
sur l'Future
objetJetez un œil aux questions SE connexes:
Comment attendre un thread qui génère son propre thread?
Executors: Comment attendre de manière synchrone la fin de toutes les tâches si les tâches sont créées de manière récursive?
la source
Je suggérerais de regarder le javadoc pour la classe Thread .
Vous disposez de plusieurs mécanismes de manipulation des threads.
Votre thread principal pourrait
join()
les trois threads en série, et ne continuerait pas tant que les trois ne seraient pas terminés.Interrogez régulièrement l'état du thread des threads générés.
Mettez tous les threads générés dans un autre
ThreadGroup
et interrogez leactiveCount()
sur leThreadGroup
et attendez qu'il atteigne 0.Configurez un type d'interface de rappel ou d'écouteur personnalisé pour la communication inter-thread.
Je suis sûr qu'il me manque encore de nombreuses autres façons.
la source
Voici une solution simple, courte, facile à comprendre et qui fonctionne parfaitement pour moi. J'avais besoin de dessiner sur l'écran lorsqu'un autre fil se terminait; mais ne pouvait pas parce que le thread principal a le contrôle de l'écran. Alors:
(1) J'ai créé la variable globale:
boolean end1 = false;
le thread le définit sur true à la fin. Cela est récupéré dans le thread principal par la boucle «postDelayed», où il est répondu.(2) Mon fil contient:
(3) Heureusement, "postDelayed" s'exécute dans le thread principal, c'est donc là que l'on vérifie l'autre thread une fois par seconde. Lorsque l'autre thread se termine, cela peut commencer ce que nous voulons faire ensuite.
(4) Enfin, démarrez le tout en cours d'exécution quelque part dans votre code en appelant:
la source
Je suppose que le moyen le plus simple est d'utiliser la
ThreadPoolExecutor
classe.c'est exactement ce dont nous avons besoin. Nous remplacerons
afterExecute()
pour obtenir des rappels une fois que chaque thread est terminé et nous remplaceronsterminated()
pour savoir quand tous les threads sont terminés.Alors voici ce que tu devrais faire
Créez un exécuteur testamentaire:
Et commencez vos discussions:
La méthode Inside
informUiThatWeAreDone();
fait tout ce que vous devez faire lorsque tous les threads sont terminés, par exemple, mettez à jour l'interface utilisateur.NOTE: N'oubliez pas d'utiliser des
synchronized
méthodes puisque vous faites votre travail en parallèle et soyez TRÈS PRUDENT si vous décidez d'appeler unesynchronized
méthode à partir d'une autresynchronized
méthode! Cela conduit souvent à des blocagesJ'espère que cela t'aides!
la source
Vous pouvez également utiliser SwingWorker, qui prend en charge le changement de propriété intégré. Voir addPropertyChangeListener () ou la méthode get () pour un exemple d'écouteur de changement d'état.
la source
Consultez la documentation Java de la classe Thread. Vous pouvez vérifier l'état du thread. Si vous placez les trois threads dans des variables membres, les trois threads peuvent lire les états de chacun.
Vous devez être un peu prudent, cependant, car vous pouvez provoquer des conditions de concurrence entre les threads. Essayez simplement d'éviter une logique compliquée basée sur l'état des autres threads. Évitez définitivement l'écriture de plusieurs threads dans les mêmes variables.
la source