web-dev-qa-db-fra.com

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

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

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

  2. Si je n'interromps jamais d'autres threads moi-même en utilisant interrupt () (par exemple parce que j'utilise d'autres moyens pour annuler mes threads de travail, comme les pilules empoisonnées et tandis que (! annulée) boucle de style [comme expliqué dans JCIP]), que fait une InterruptedException signifie alors? Que dois-je faire après en avoir attrapé un? Arrêter mon application?

82
SyntaxT3rr0r

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

En pratique, les cas d'utilisation normaux de interrupt() impliquent une sorte de framework ou de gestionnaire disant à un thread de travail d'arrêter ce qu'il fait. Si le thread de travail est "averti des interruptions", il remarquera qu'il a été interrompu via une exception ou en vérifiant périodiquement son indicateur d'interruption. En constatant qu'il a été interrompu, un fil de bonne conduite 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 framework Java ou à partir d'un thread de travail. Et lorsqu'il est interrompu, votre code doit abandonner ce qu'il est) faisant et se terminant par les moyens les plus appropriés. Selon la façon dont votre code a été appelé, cela peut être fait en renvoyant 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 il a été interrompu, et il ne sait certainement pas s'il existe 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 pourriez faire valoir que InterruptedException est une exception inattendue; c'est à dire un bug. Dans ce cas, vous devez traiter l'exception comme vous le feriez pour d'autres bogues; par exemple. encapsulez-le dans une exception non vérifiée, et interceptez-le et enregistrez-le au même moment que vous traitez avec d'autres exceptions non vérifiées inattendues. (Alternativement, votre application pourrait simplement ignorer l'interruption et continuer à faire ce qu'elle faisait.)


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

Par exemple, si vos objets Runnable sont exécutés à l'aide d'un ExecutorService et que shutdownNow() est appelée sur le service. Et en théorie, tout pool de threads tiers ou framework de gestion de threads pourrait légitimement faire quelque chose comme ça.

2) Si je n'interromps jamais d'autres threads moi-même en utilisant interrupt () ... que signifie un InterruptedException? Que dois-je faire après en avoir attrapé un? Arrêter mon application?

Vous devez analyser la base de code pour comprendre ce qui fait les appels interrupt() 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 InterruptedException est lancé, je vous conseille de le traiter comme une erreur grave; par exemple. imprimer une trace de pile dans le fichier journal et fermer l'application. (Évidemment, ce n'est pas toujours la bonne réponse ... mais le fait est que c'est "un bug", 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 la Thread.interrupt() et de regarder la pile des appels.

48
Stephen C

Si vous décidez d'intégrer votre code avec d'autres bibliothèques, ils peuvent appeler interrupt() sur 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 pourrait s'exécuter à l'avenir. par exemple. allez-vous le mettre dans une bibliothèque? Un contenant ? Comment les autres vont-ils l'utiliser? Allez-vous le réutiliser?

12
Brian Agnew

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

Cependant, vous ne devez pas traiter un InterruptedException seul comme une "commande quit". Au lieu de cela, vous devez 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 fait Object.notify(). De la même manière que vous vérifieriez l'état actuel après vous être réveillé 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.FutureTask A une méthode isCancelled().

Échantillon 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();
}
9
Øyvind Bakksjø

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à, qu'un morceau particulier de code de bas niveau (classe) ne devrait pas dépendre de la mise en œuvre de l'ensemble du système. Cela dit, vous devez prendre des décisions "architecturales" (comme la plate-forme sur laquelle exécuter).

Les interruptions inattendues possibles provenant du JRE sont des tâches annulées dans Java.util.concurrent et la fermeture des applets.

La gestion des interruptions de thread est généralement mal écrite. Par conséquent, je suggère la décision architecturale pour éviter de provoquer des interruptions lorsque cela est possible. Cependant, les interruptions de gestion de code doivent toujours être écrites correctement. Impossible d'interrompre la plateforme pour le moment.

3

Vous pouvez l'apprendre en créant votre propre classe de threads (en étendant Java.lang.Thread) Et en remplaçant la méthode interrupt(), dans laquelle vous enregistrez la trace de pile dans, disons, un champ String, puis transférez vers super. interrompre().

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();
    }
}
2
weekens

Comme déjà mentionné, une autre bibliothèque peut interrompre vos threads. Même si la bibliothèque n'a pas un 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.

1
mangoDrunk

Le InterruptedException dit qu'une routine peut être interrompue, mais pas nécessairement ce qu'elle sera.

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

0
Ash

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 d'autres threads moi-même, qu'est-ce qui peut déclencher une InterruptedException?

Premièrement, 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 laisser son propriétaire suivre la procédure d'interruption; il contient la politique d'interruption, pas votre code de tâche; soyez au moins courtois pour mettre le drapeau d'interruption!

Il existe de nombreuses façons pour lesquelles il peut y avoir des interruptions, des délais d'attente, des interruptions JVM, etc.

Si je n'interromps jamais d'autres threads moi-même en utilisant interrupt () (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 (! Cancelled) [comme expliqué dans JCIP]), qu'est-ce que signifie alors une InterruptedException? Que dois-je faire après en avoir attrapé 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é, dites 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, après avoir attrapé IE soit le relancer plus haut dans la pile des appels ou après avoir fait quelque chose (peut-être en train de se connecter), réinitialisez l'état interrompu afin que le code qui possède ce thread, lorsque le contrôle l'atteint, peut apprendre que le thread a été interrompu et donc prendre des mesures comme il le fera car lui seul connaît la politique d'interruption.

J'espère que cela vous a aidé.

0