Qui appelle la méthode Java Thread interruption () si je ne le suis pas?

87

J'ai lu et relu Java Concurrency en pratique, j'ai lu plusieurs fils de discussion ici sur le sujet, j'ai lu l'article d'IBM Dealing with InterruptedException et pourtant il y a quelque chose que je ne saisis tout simplement pas et qui, je pense, peut être cassé en deux questions:

  1. Si je n'interromps jamais moi-même d'autres threads, qu'est-ce qui peut déclencher une InterruptedException ?

  2. Si je n'interromps jamais jamais d'autres threads moi-même en utilisant interromp () (disons parce que j'utilise d'autres moyens pour annuler mes threads de travail, comme les pilules empoisonnées et la boucle de style while (! Annulé) [comme les deux expliqués dans JCIP]), signifie alors une InterruptedException ? Que suis-je censé faire en attrapant un? Arrêter mon application?

SyntaxeT3rr0r
la source

Réponses:

50

Le mécanisme d'interruption de thread est le moyen préféré pour qu'un thread (coopérant) réponde à une demande d'arrêt de ce qu'il fait. N'importe quel fil (y compris le fil lui-même je pense) pourrait appeler interrupt()un fil.

En pratique, les cas d'utilisation normaux interrupt()impliquent une sorte de cadre ou de gestionnaire indiquant à un thread de travail d'arrêter ce qu'il fait. Si le thread de travail est "sensible aux interruptions", il remarquera qu'il a été interrompu via une exception, ou en vérifiant périodiquement son indicateur d'interruption. En remarquant qu'il a été interrompu, un thread bien comporté abandonnerait ce qu'il fait et se terminerait.

En supposant le cas d'utilisation ci-dessus, votre code est susceptible d'être interrompu s'il est exécuté dans un cadre Java ou à partir d'un thread de travail. Et quand il est interrompu, votre code doit abandonner ce qu'il fait et se terminer par les moyens les plus appropriés. Selon la façon dont votre code a été appelé, cela peut être fait en retournant ou en lançant une exception appropriée. Mais il ne devrait probablement pas appeler System.exit(). (Votre application ne sait pas nécessairement pourquoi elle a été interrompue, et elle ne sait certainement pas s'il y a d'autres threads qui doivent être interrompus par le framework.)

D'un autre côté, si votre code n'est pas conçu pour s'exécuter sous le contrôle d'un framework, vous pouvez affirmer qu'il InterruptedExceptions'agit d'une exception inattendue; c'est à dire un bug. Dans ce cas, vous devez traiter l'exception comme vous le feriez pour les autres bogues; par exemple, enveloppez-le dans une exception non vérifiée, et attrapez-la et enregistrez-la au même moment où vous traitez avec d'autres exceptions non vérifiées inattendues. (Sinon, votre application pourrait simplement ignorer l'interruption et continuer à faire ce qu'elle faisait.)


1) Si je n'interromps jamais moi-même d'autres threads, qu'est-ce qui peut déclencher une InterruptedException?

Un exemple est si vos Runnableobjets sont exécutés à l'aide d'un ExecutorServiceet shutdownNow()est appelé sur le service. Et en théorie, tout pool de threads tiers ou cadre de gestion de threads pourrait légitimement faire quelque chose comme ça.

2) Si je n'interromps jamais moi-même d'autres threads en utilisant interrupt () ... que signifie InterruptedExceptionalors? Que dois-je faire en attrapant un? Arrêter mon application?

Vous devez analyser la base de code pour déterminer ce qui fait les interrupt()appels et pourquoi. Une fois que vous avez compris cela, vous pouvez déterminer ce que >> votre << partie de l'application doit faire.

Jusqu'à ce que vous sachiez pourquoi InterruptedExceptionest jeté, je vous conseillerais de le traiter comme une grave erreur; par exemple, imprimez une trace de pile dans le fichier journal et arrêtez l'application. (Évidemment, ce n'est pas toujours la bonne réponse ... mais le fait est qu'il s'agit d'un "bogue", et il doit être porté à l'attention du développeur / mainteneur.)

3) Comment savoir qui / quoi appelle interrupt()?

Il n'y a pas de bonne réponse à cela. Le mieux que je puisse suggérer est de définir un point d'arrêt sur le Thread.interrupt()et de regarder la pile d'appels.

Stephen C
la source
12

Si vous décidez d'intégrer votre code avec d'autres bibliothèques, elles peuvent faire appel interrupt()à votre code. Par exemple, si vous décidez à l'avenir d'exécuter votre code dans un ExecutorService , cela peut forcer un arrêt via interrupt().

Pour le dire brièvement, je considérerais non seulement où votre code s'exécute maintenant , mais dans quel contexte il peut s'exécuter à l'avenir. par exemple, allez-vous le mettre dans une bibliothèque? Un contenant ? Comment d'autres personnes l'utiliseront-elles? Allez-vous le réutiliser?

Brian Agnew
la source
Je pensais que seul shutdownNow appelle la méthode interrupt (). Est-ce également vrai pour l'arrêt?
Harinder
9

Comme d'autres l'ont souligné, interrompre un thread (en fait, interrompre un appel de blocage) est généralement utilisé dans le but de quitter proprement ou d'annuler une activité en cours.

Cependant, vous ne devez pas traiter un InterruptedExceptionseul comme une "commande de sortie". Au lieu de cela, vous devriez considérer les interruptions comme un moyen de contrôler l'état d'exécution des threads, de la même manière que le Object.notify()fait. De la même manière que vous vérifieriez l'état actuel après le réveil d'un appel à Object.wait()(vous ne supposez pas que le réveil signifie que votre condition d'attente a été satisfaite), après avoir été poussé avec une interruption, vous devriez vérifier pourquoi vous avez été interrompu . Il existe généralement un moyen de le faire. Par exemple, java.util.concurrent.FutureTaska une isCancelled()méthode.

Exemple de code:

public void run() {
    ....
    try {
        .... // Calls that may block.
    } catch (InterruptedException e) {
        if (!running) {  // Add preferred synchronization here.
            return; // Explicit flag says we should stop running.
        }
        // We were interrupted, but the flag says we're still running.
        // It would be wrong to always exit here. The interrupt 'nudge'
        // could mean something completely different. For example, it
        // could be that the thread was blocking on a read from a particular
        // file, and now we should read from a different file.
        // Interrupt != quit (not necessarily).
    }
    ....
}
public void stop() {
    running = false; // Add preferred synchronization here.
    myThread.interrupt();
}
Øyvind Bakksjø
la source
3

Le problème avec la question est «je». «I» fait généralement référence à une seule instance d'une classe. Je veux dire par là que tout élément particulier de code de bas niveau (classe) ne devrait pas s'appuyer sur la mise en œuvre de l'ensemble du système. Cela dit, vous devez prendre des décisions «architecturales» (comme sur quelle plate-forme fonctionner).

Les éventuelles interruptions inattendues provenant du JRE sont des tâches annulées dans java.util.concurrentet l'arrêt des applets.

La gestion des interruptions de thread est généralement écrite de manière incorrecte. Par conséquent, je suggère la décision architecturale d'éviter de provoquer des interruptions lorsque cela est possible. Cependant, les interruptions de gestion de code doivent toujours être écrites correctement. Impossible de supprimer les interruptions de la plate-forme maintenant.

Tom Hawtin - Tacle
la source
Salut Tom, je me souviens de votre nom de cljp;) Eh bien, précisément: je n'ai jamais eu à lancer d' interruption () moi-même ... À moins que je n'attrape une InterruptedException et que je doive réaffirmer le statut interrompu mais ce n'est toujours pas 100% clair pour moi. Je suis nouveau ici et surpris par le nombre de votes positifs et de réponses / commentaires (à la fois les bons et les mauvais): évidemment, c'est un sujet qui n'est pas trivial ou, du moins, généralement mal expliqué. Cela dit, grâce à tous les messages, je commence à avoir une image plus claire de ce qui se passe :)
SyntaxeT3rr0r
3

Vous pouvez apprendre cela en créant votre propre classe de thread (extension java.lang.Thread) et interrupt()méthode de substitution, dans laquelle vous enregistrez la trace de pile dans, par exemple, un champ String, puis transférez vers super.interrupt ().

public class MyThread extends Thread {

    public volatile String interruptStacktrace; // Temporary field for debugging purpose.

    @Override
    public void interrupt() {
        interruptStacktrace = dumpStack(); // You implement it somehow...

        super.interrupt();
    }
}
weekens
la source
1

Comme déjà mentionné, une autre bibliothèque peut interrompre vos threads. Même si la bibliothèque n'a pas d'accès explicite aux threads à partir de votre code, ils peuvent toujours obtenir la liste des threads en cours d'exécution et les interrompre de cette façon avec la méthode suivante .

mangue ivre
la source
1

Je pense que je comprends pourquoi vous êtes un peu confus au sujet de l'interruption. Veuillez considérer mes réponses en ligne:

Si je n'interromps jamais moi-même d'autres threads, qu'est-ce qui peut déclencher une InterruptedException ?

Tout d'abord, vous pouvez interrompre d'autres threads; Je sais que dans JCiP, il est mentionné que vous ne devez jamais interrompre les threads que vous ne possédez pas; cependant, cette déclaration doit être bien comprise. Cela signifie que votre code qui pourrait s'exécuter dans n'importe quel thread arbitraire ne devrait pas gérer les interruptions car puisqu'il n'est pas le propriétaire du thread, il n'a aucune idée de sa politique d'interruption. Vous pouvez donc demander une interruption sur d'autres threads, mais laissez son propriétaire suivre le cours de l'action d'interruption; il contient la politique d'interruption, pas votre code de tâche; au moins, soyez courtois pour définir le drapeau d'interruption!

Il existe de nombreuses raisons pour lesquelles des interruptions peuvent encore se produire, des délais d'expiration, des interruptions JVM, etc.

Si je n'interromps jamais jamais d'autres threads moi-même en utilisant interromp () (disons parce que j'utilise d'autres moyens pour annuler mes threads de travail, comme les pilules empoisonnées et la boucle de style while (! Annulé) [comme les deux expliqués dans JCIP]), signifie alors une InterruptedException? Que suis-je censé faire en attrapant un? Arrêter mon application?

Vous devez être très prudent ici; si vous possédez le thread qui a lancé InterruptedException (IE), alors vous savez quoi faire après l'avoir attrapé, disons que vous pouvez arrêter votre application / service ou vous pouvez remplacer ce thread tué par un nouveau! Cependant, si vous ne possédez pas le thread, lors de la capture d'IE, soit le relancez plus haut dans la pile d'appels, soit après avoir fait quelque chose (peut-être en cours de journalisation), réinitialisez le statut interrompu afin que le code qui possède ce thread, lorsque le contrôle l'atteigne, puisse apprenez que le thread a été interrompu et par conséquent, prenez les mesures nécessaires, car lui seul connaît la politique d'interruption.

J'espère que cela a aidé.

nawazish-stackoverflow
la source
0

Le InterruptedExceptiondit qu'une routine peut être interrompue, mais pas nécessairement qu'elle le sera.

Si vous n'attendez pas l'interruption, vous devez la traiter comme toute autre exception inattendue. Si c'est dans une section critique où une exception inattendue pourrait avoir des conséquences odieuses, il peut être préférable d'essayer de nettoyer les ressources et d'arrêter en douceur (car obtenir les signaux d'interruption que votre application bien conçue qui ne repose pas sur des interruptions est utilisée d'une certaine manière, il n'a pas été conçu, et il doit donc y avoir quelque chose qui ne va pas). Sinon, si le code en question est quelque chose de non critique ou de trivial, vous pouvez ignorer (ou enregistrer) l'interruption et continuer.

Cendre
la source