Quelle est la différence entre les modes de manipulation suivants InterruptedException
? Quelle est la meilleure façon de procéder?
try{
//...
} catch(InterruptedException e) {
Thread.currentThread().interrupt();
}
OU
try{
//...
} catch(InterruptedException e) {
throw new RuntimeException(e);
}
EDIT: Je voudrais également savoir dans quels scénarios ces deux sont utilisés.
Réponses:
Vous êtes probablement venu poser cette question parce que vous avez appelé une méthode qui lance
InterruptedException
.Tout d'abord, vous devriez voir
throws InterruptedException
de quoi il s'agit: une partie de la signature de la méthode et un résultat possible de l'appel de la méthode que vous appelez. Commencez donc par comprendre que anInterruptedException
est un résultat parfaitement valide de l'appel de méthode.Maintenant, si la méthode que vous appelez lève une telle exception, que devrait faire votre méthode? Vous pouvez trouver la réponse en réfléchissant à ce qui suit:
Est-il logique que la méthode que vous implémentez lance un
InterruptedException
? Autrement dit, est-ceInterruptedException
un résultat raisonnable lorsque vous appelez votre méthode?Si oui , alors
throws InterruptedException
devrait faire partie de votre signature de méthode, et vous devriez laisser l'exception se propager (c'est-à-dire ne pas l'attraper du tout).Si non , vous ne devez pas déclarer votre méthode avec
throws InterruptedException
et vous devez (devez!) Intercepter l'exception. Maintenant, deux choses sont importantes à garder à l'esprit dans cette situation:Quelqu'un a interrompu votre fil. Que quelqu'un est probablement impatient d'annuler l'opération, de terminer le programme avec élégance ou autre chose. Vous devez être poli avec cette personne et revenir de votre méthode sans plus tarder.
Même si votre méthode parvient à produire une valeur de retour raisonnable en cas de problème,
InterruptedException
le fait que le thread a été interrompu peut toujours être important. En particulier, le code qui appelle votre méthode peut être intéressé à savoir si une interruption s'est produite lors de l'exécution de votre méthode. Vous devez donc consigner le fait qu'une interruption a eu lieu en définissant le drapeau interrompu:Thread.currentThread().interrupt()
À présent, il devrait être clair que faire
throw new RuntimeException(e)
est une mauvaise idée. Ce n'est pas très poli avec l'appelant. Vous pouvez inventer une nouvelle exception d'exécution, mais la cause première (quelqu'un veut que le thread arrête l'exécution) peut être perdue.Autres exemples:
Ce message a été réécrit en tant qu'article ici .
la source
interrupt()
pour conserver le statut interrompu. Quelle est la raison derrière ne pas faire ça sur unThread.sleep()
?Thread.currentThread.interrupt()
unInterruptedException
bloc catch ne définira que le drapeau d'interruption. Cela ne fera pasInterruptedException
jeter / attraper un autre dans unInterruptedException
bloc de capture externe .Il se trouve que je lisais ce sujet ce matin en allant travailler dans Java Concurrency In Practice de Brian Goetz. Fondamentalement, il dit que vous devez faire trois choses
Propagez la
InterruptedException
- Déclarez votre méthode pour lancer la vérificationInterruptedException
afin que votre appelant doive y faire face.Restaurer l'interruption - Parfois, vous ne pouvez pas lancer
InterruptedException
. Dans ces cas, vous devez intercepterInterruptedException
et restaurer l'état d'interruption en appelant lainterrupt()
méthode sur lecurrentThread
afin que le code situé plus haut dans la pile d'appels puisse voir qu'une interruption a été émise et revenir rapidement de la méthode. Remarque: ceci n'est applicable que lorsque votre méthode a une sémantique "try" ou "best effort", c'est-à-dire que rien de critique ne se produira si la méthode n'atteint pas son objectif. Par exemple,log()
ousendMetric()
peut être une telle méthode, ouboolean tryTransferMoney()
, mais pasvoid transferMoney()
. Voir ici pour plus de détails.Uninterruptibles
.Uninterruptibles
reprendre le code passe-partout comme dans l'exemple de tâche non annulable dans JCIP § 7.1.3.la source
Qu'essayez-vous de faire?
Le
InterruptedException
est levé lorsqu'un thread est en attente ou en sommeil et qu'un autre thread l'interrompt en utilisant lainterrupt
méthode en classeThread
. Donc, si vous interceptez cette exception, cela signifie que le thread a été interrompu. Habituellement, il est inutile d'appeler àThread.currentThread().interrupt();
nouveau, sauf si vous voulez vérifier l'état «interrompu» du thread ailleurs.En ce qui concerne votre autre option de lancer un
RuntimeException
, cela ne semble pas une chose très sage à faire (qui va attraper cela? Comment sera-t-il géré?) Mais il est difficile d'en dire plus sans informations supplémentaires.la source
Thread.currentThread().interrupt()
définit à nouveau l'indicateur interrompu, ce qui est utile en effet si nous voulons nous assurer que l'interruption est remarquée et traitée à un niveau supérieur.Pour moi, l'élément clé à ce sujet est: une InterruptedException n'est pas quelque chose qui ne va pas, c'est le fil qui fait ce que vous lui avez dit de faire. Par conséquent, le relancer enveloppé dans une RuntimeException n'a aucun sens.
Dans de nombreux cas, il est logique de renvoyer une exception enveloppée dans une exception RuntimeException lorsque vous dites, je ne sais pas ce qui s'est mal passé ici et je ne peux rien faire pour le corriger, je veux juste qu'il sorte du flux de traitement actuel et appuyez sur le gestionnaire d'exceptions à l'échelle de l'application que j'ai pour qu'il puisse le journaliser. Ce n'est pas le cas avec une InterruptedException, c'est juste le thread qui répond à avoir appelé interrupt (), il lance l'InterruptedException afin d'aider à annuler le traitement du thread en temps opportun.
Alors propagez l'InterruptedException, ou mangez-le intelligemment (c'est-à-dire à un endroit où il aura accompli ce qu'il était censé faire) et réinitialisez le drapeau d'interruption. Notez que l'indicateur d'interruption est effacé lorsque l'interruptionException est levée; l'hypothèse que les développeurs de la bibliothèque Jdk font est que la capture de l'exception revient à la gérer, donc par défaut le drapeau est effacé.
Donc, la première façon est certainement meilleure, le deuxième exemple publié dans la question n'est utile que si vous ne vous attendez pas à ce que le thread soit réellement interrompu, et l'interrompre équivaut à une erreur.
Voici une réponse que j'ai écrite décrivant le fonctionnement des interruptions, avec un exemple . Vous pouvez voir dans l'exemple de code où il utilise l'InterruptedException pour sortir d'une boucle while dans la méthode d'exécution de Runnable.
la source
Le choix par défaut correct est d'ajouter InterruptedException à votre liste de lancers. Une interruption indique qu'un autre thread souhaite que votre thread se termine. La raison de cette demande n'est pas rendue évidente et est entièrement contextuelle, donc si vous n'avez pas de connaissances supplémentaires, vous devez supposer que c'est juste un arrêt amical, et tout ce qui évite cet arrêt est une réponse non amicale.
Java ne lèvera pas au hasard InterruptedException, tous les conseils n'affecteront pas votre application, mais j'ai rencontré un cas où le développeur suivant la stratégie "swallow" est devenu très gênant. Une équipe avait développé un large éventail de tests et utilisé beaucoup Thread.Sleep. Maintenant, nous avons commencé à exécuter les tests sur notre serveur CI, et parfois, en raison de défauts dans le code, nous nous retrouvions coincés dans des attentes permanentes. Pour aggraver la situation, lorsque vous tentiez d'annuler le travail CI, il ne se fermait jamais car le thread. L'interruption qui était destinée à abandonner le test n'a pas interrompu le travail. Nous avons dû nous connecter à la boîte et tuer manuellement les processus.
Donc, pour faire court, si vous lancez simplement l'exception InterruptedException, vous correspondez à l'intention par défaut de la fin de votre thread. Si vous ne pouvez pas ajouter InterruptedException à votre liste de lancers, je l'envelopperais dans une RuntimeException.
Il y a un argument très rationnel à faire valoir que InterruptedException devrait être une RuntimeException elle-même, car cela encouragerait une meilleure gestion "par défaut". Ce n'est pas une RuntimeException uniquement parce que les concepteurs se sont tenus à une règle catégorique selon laquelle une RuntimeException devrait représenter une erreur dans votre code. Puisqu'une InterruptedException ne résulte pas directement d'une erreur dans votre code, ce n'est pas le cas. Mais la réalité est que souvent une InterruptedException se produit parce qu'il y a une erreur dans votre code, (c'est-à-dire une boucle sans fin, un verrou mortel), et l'Interruption est une autre méthode d'un autre thread pour traiter cette erreur.
Si vous savez qu'il y a un nettoyage rationnel à faire, faites-le. Si vous connaissez une cause plus profonde de l'interruption, vous pouvez prendre en charge une gestion plus complète.
Donc, en résumé, vos choix de manipulation doivent suivre cette liste:
la source
Je voulais juste ajouter une dernière option à ce que la plupart des gens et des articles mentionnent. Comme l'a indiqué mR_fr0g, il est important de gérer correctement l'interruption soit par:
Propager l'exception InterruptException
Restaurer l'état d'interruption sur le thread
Ou en plus:
Il n'y a rien de mal à gérer l'interruption de manière personnalisée selon vos circonstances. Comme une interruption est une demande de résiliation, par opposition à une commande forcée, il est parfaitement valide de terminer un travail supplémentaire pour permettre à l'application de traiter la demande avec élégance. Par exemple, si un thread est en veille, en attente d'E / S ou d'une réponse matérielle, lorsqu'il reçoit l'interruption, il est parfaitement valide de fermer correctement toutes les connexions avant de terminer le thread.
Je recommande fortement de comprendre le sujet, mais cet article est une bonne source d'informations: http://www.ibm.com/developerworks/java/library/j-jtp05236/
la source
Je dirais que dans certains cas, c'est ok de ne rien faire. Ce n'est probablement pas quelque chose que vous devriez faire par défaut, mais au cas où il ne devrait y avoir aucun moyen pour que l'interruption se produise, je ne sais pas quoi faire d'autre (probablement une erreur de journalisation, mais cela n'affecte pas le flux du programme).
Un cas serait dans le cas où vous avez une file d'attente de tâches (blocage). Dans le cas où vous avez un thread démon qui gère ces tâches et que vous n'interrompez pas le thread par vous-même (à ma connaissance, le jvm n'interrompt pas les threads du démon à l'arrêt jvm), je ne vois aucun moyen pour que l'interruption se produise, et donc cela pourrait être juste ignoré. (Je sais qu'un thread démon peut être tué par le jvm à tout moment et ne convient donc pas dans certains cas).
EDIT: Un autre cas peut être des blocs gardés, au moins basés sur le tutoriel d'Oracle à: http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
la source