Je veux exécuter un thread pendant un certain temps. S'il n'est pas terminé dans ce délai, je veux le tuer, lever une exception ou le gérer d'une manière ou d'une autre. Comment ceci peut être fait?
Une façon de le faire comme je l'ai compris à partir de ce thread est d'utiliser une TimerTask dans la méthode run () du Thread.
Existe-t-il de meilleures solutions pour cela?
EDIT: Ajout d'une prime car j'avais besoin d'une réponse plus claire. Le code ExecutorService donné ci-dessous ne résout pas mon problème. Pourquoi devrais-je dormir () après l'exécution (du code - je n'ai aucune poignée sur ce morceau de code)? Si le code est terminé et que sleep () est interrompu, comment cela peut-il être un timeOut?
La tâche qui doit être exécutée n'est pas sous mon contrôle. Il peut s'agir de n'importe quel morceau de code. Le problème est que ce morceau de code peut s'exécuter dans une boucle infinie. Je ne veux pas que cela se produise. Donc, je veux juste exécuter cette tâche dans un thread séparé. Le thread parent doit attendre la fin de ce thread et doit connaître l'état de la tâche (c'est-à-dire s'il a expiré ou si une exception s'est produite ou si c'est un succès). Si la tâche entre dans une boucle infinie, mon thread parent continue d'attendre indéfiniment, ce qui n'est pas une situation idéale.
la source
sleep()
n'était qu'un talon pour représenter une «tâche de longue durée». Il suffit de le remplacer par votre vraie tâche;)interrupt()
appels sur son thread ... tous les appels "bloquants" ne le font pas, comme j'ai essayé de le souligner dans ma réponse. Les spécificités de la tâche que vous essayez d'interrompre font une énorme différence dans l'approche à utiliser. Plus d'informations sur la tâche seraient utiles.Réponses:
En effet plutôt utiliser à la
ExecutorService
place deTimer
, voici un SSCCE :Jouez un peu avec l'
timeout
argument dans laFuture#get()
méthode, par exemple augmentez-le à 5 et vous verrez que le fil se termine. Vous pouvez intercepter le délai d'expiration dans lecatch (TimeoutException e)
bloc.Mise à jour: pour clarifier un malentendu conceptuel, le
sleep()
n'est pas requis. Il est juste utilisé à des fins de démonstration / SSCCE. Faites simplement votre longue tâche à la place desleep()
. Dans votre longue tâche, vous devriez vérifier si le thread n'est pas interrompu comme suit:la source
Thread.sleep(4000)
par une autre instruction longue et l'exemple ne fonctionnera pas. En d'autres termes, cet exemple ne fonctionnerait que si leTask
est conçu pour comprendre leThread.isInterrupted()
changement de statut.Il n'y a pas de méthode fiable à 100% pour effectuer une tâche ancienne. La tâche doit être écrite avec cette capacité à l'esprit.
Les bibliothèques Java de base aiment
ExecutorService
annuler les tâches asynchrones avec desinterrupt()
appels sur le thread de travail. Ainsi, par exemple, si la tâche contient une sorte de boucle, vous devez vérifier son état d'interruption à chaque itération. Si la tâche effectue des opérations d'E / S, elles doivent également être interruptibles et leur configuration peut être délicate. Dans tous les cas, gardez à l'esprit que le code doit vérifier activement les interruptions; définir une interruption ne fait rien nécessairement.Bien sûr, si votre tâche est une simple boucle, vous pouvez simplement vérifier l'heure actuelle à chaque itération et abandonner lorsqu'un délai spécifié s'est écoulé. Un thread de travail n'est pas nécessaire dans ce cas.
la source
execute()
méthode de l'interface parentExecutor
peut exécuter une tâche dans le thread appelant. Il n'y a pas de déclaration similaire pour lessubmit()
méthodes deExecutorService
cesFuture
instances de retour . L'implication du service est qu'il existe des threads de travail qui doivent être nettoyés via l'arrêt et que les tâches sont exécutées de manière asynchrone. Cela dit, rien dans le contrat ne dit qu'ilExecutorService
est interdit d'exécuter des tâches dans le thread de soumission; ces garanties proviennent des API d'implémentation, comme lesExecutors
usines.Pensez à utiliser une instance d' ExecutorService . Les deux méthodes
invokeAll()
etinvokeAny()
sont disponibles avec untimeout
paramètre.Le thread actuel se bloquera jusqu'à ce que la méthode soit terminée (je ne sais pas si cela est souhaitable) soit parce que la ou les tâches se sont terminées normalement ou que le délai a été atteint. Vous pouvez inspecter le
Future
(s) retour (s) pour déterminer ce qui s'est passé.la source
En supposant que le code de thread est hors de votre contrôle:
De la documentation Java mentionnée ci-dessus:
Conclusion:
Assurez-vous que tous les threads peuvent être interrompus, sinon vous avez besoin d'une connaissance spécifique du thread - comme avoir un indicateur à définir. Peut-être pouvez-vous exiger que la tâche vous soit donnée avec le code nécessaire pour l'arrêter - définissez une interface avec une
stop()
méthode. Vous pouvez également avertir lorsque vous n'avez pas réussi à arrêter une tâche.la source
BalusC a déclaré:
Mais si vous remplacez
Thread.sleep(4000);
parfor (int i = 0; i < 5E8; i++) {}
alors il ne se compile pas, car la boucle vide ne lance pas unInterruptedException
.Et pour que le thread soit interruptible, il doit lancer un
InterruptedException
.Cela me semble être un problème grave. Je ne vois pas comment adapter cette réponse pour travailler avec une tâche générale de longue durée.
Modifié pour ajouter: j'ai reformulé ceci comme une nouvelle question: [ interrompre un thread après un temps fixe, doit-il lever InterruptedException? ]
la source
Je pense que vous devriez jeter un coup d'œil aux mécanismes de gestion des accès concurrents (les threads s'exécutant dans des boucles infinies ne sonnent pas bien en soi, btw). Assurez-vous de lire un peu sur le sujet "Tuer" ou "arrêter" les discussions .
Ce que vous décrivez ressemble beaucoup à un "rendez-vous", donc vous voudrez peut-être jeter un œil au CyclicBarrier .
Il peut y avoir d'autres constructions (comme l'utilisation de CountDownLatch par exemple) qui peuvent résoudre votre problème (un thread attend avec un délai d'attente pour le verrou, l'autre doit décompter le verrou s'il a fait son travail, ce qui libérerait votre premier thread soit après une temporisation ou lorsque le compte à rebours du verrou est invoqué).
Je recommande généralement deux livres dans ce domaine: la programmation simultanée en Java et la concurrence Java en pratique .
la source
J'ai créé une classe d'aide juste pour cela il y a quelque temps. Fonctionne très bien:
Cela s'appelle comme ceci:
la source
Je vous poste un morceau de code qui montre comment résoudre le problème. Par exemple, je lis un fichier. Vous pouvez utiliser cette méthode pour une autre opération, mais vous devez implémenter la méthode kill () afin que l'opération principale soit interrompue.
J'espère que ça aide
Cordialement
la source
Voici ma classe d'assistance vraiment simple à utiliser pour exécuter ou appeler un morceau de code Java :-)
Ceci est basé sur l'excellente réponse de BalusC
la source
L'extrait de code suivant démarrera une opération dans un thread séparé, puis attendra jusqu'à 10 secondes pour que l'opération se termine. Si l'opération ne se termine pas à temps, le code tentera d'annuler l'opération, puis poursuivra son chemin joyeux. Même si l'opération ne peut pas être annulée facilement, le thread parent n'attendra pas la fin du thread enfant.
La
getExecutorService()
méthode peut être mise en œuvre de plusieurs façons. Si vous n'avez pas d'exigences particulières, vous pouvez simplement demanderExecutors.newCachedThreadPool()
un pool de threads sans limite supérieure sur le nombre de threads.la source
SomeClass
etFuture
?Une chose que je n'ai pas vue mentionnée est que tuer les threads est généralement une mauvaise idée. Il existe des techniques pour rendre les méthodes threadées proprement abandonnées , mais c'est différent de simplement tuer un thread après un délai d'expiration.
Le risque avec ce que vous proposez est que vous ne savez probablement pas dans quel état sera le thread lorsque vous le tuerez - vous risquez donc d'introduire de l'instabilité. Une meilleure solution consiste à vous assurer que votre code threadé ne se bloque pas lui-même ou qu'il répond bien à une demande d'abandon.
la source
Excellente réponse de BalusC:
mais juste pour ajouter que le timeout lui-même n'interrompt pas le thread lui-même. même si vous vérifiez avec ((Thread.interrupted ()) dans votre tâche. si vous voulez vous assurer que le thread est arrêté, vous devez également vous assurer que future.cancel () est invoqué lorsque l'exception d'expiration est interceptée.
la source
Je pense que la réponse dépend principalement de la tâche elle-même.
Si la première réponse est oui et la seconde est non, vous pouvez rester aussi simple que cela:
Si ce n'est pas une option, veuillez restreindre vos exigences - ou montrer du code.
la source
Je cherchais un ExecutorService qui peut interrompre tous les Runnables expirés exécutés par lui, mais n'en ai trouvé aucun. Après quelques heures, j'en ai créé un comme ci-dessous. Cette classe peut être modifiée pour améliorer la robustesse.
Usage:
la source
Maintenant, je rencontre un problème comme celui-ci. Il arrive de décoder l'image. Le processus de décodage prend trop de temps pour que l'écran reste noir. l ajouter un contrôleur de temps: lorsque le temps est trop long, puis surgissez du fil actuel. Ce qui suit est le diff:
la source
J'ai eu le même problème. J'ai donc trouvé une solution simple comme celle-ci.
Garantit que si le bloc ne s'est pas exécuté dans le délai imparti. le processus se terminera et lèvera une exception.
exemple :
la source
Dans la solution proposée par BalusC , le thread principal restera bloqué pendant la période de temporisation. Si vous disposez d'un pool de threads avec plusieurs threads, vous aurez besoin du même nombre de threads supplémentaires qui utiliseront Future.get (long timeout, TimeUnit unit) blocking call pour attendre et fermer le thread s'il dépasse le délai d'expiration.
Une solution générique à ce problème consiste à créer un décorateur ThreadPoolExecutor qui peut ajouter la fonctionnalité de délai d'expiration. Cette classe Decorator doit créer autant de threads que ThreadPoolExecutor, et tous ces threads doivent être utilisés uniquement pour attendre et fermer ThreadPoolExecutor.
La classe générique doit être implémentée comme ci-dessous:
Le décorateur ci-dessus peut être utilisé comme ci-dessous:
la source