1. Introduction
Cet article enregistre quelques points de connaissance sur le mécanisme d'interruption dans le multithreading Java. Il consiste principalement en la différence entre la méthode d'arrêt, les méthodes interrompues () et INTERRUPT (), et effectue une analyse simple à partir de l'implémentation du code source.
Il existe 3 façons de terminer les fils de course en Java
①Le thread sort normalement, c'est-à-dire que la méthode run () a été exécutée
② Utilisez la méthode stop () dans la classe de threads pour terminer avec force le thread. Cependant, la méthode stop () a expiré et n'est pas recommandée pour l'utiliser
Utilisez le mécanisme d'interruption
Il n'y a rien à faire lorsque le thread sort normalement. Le mécanisme d'interruption est introduit en détail ci-dessous. Examinons d'abord le code source de la méthode stop (). La clé est les commentaires sur le code source. Il explique pourquoi stop () n'est pas sûr, quel fil est arrêté par la méthode stop ()?
/ *** force le thread à arrêter l'exécution. * <p> * S'il y a un gestionnaire de sécurité installé, sa méthode <code> checkAccess </code> * est appelée avec <code> ce </code> * comme argument. Cela peut entraîner la mise en place d'un * <code> SecurityException </code> (dans le thread actuel). * <p> * Si ce thread est différent du thread actuel (c'est-à-dire que le thread * actuel essaie d'arrêter un thread autre que lui-même), la méthode <code> du gestionnaire de sécurité </code> (avec un argument * <code> RuntimePermer ("Stopthread") </ / code> est appelé dans un argument * à nouveau, ce qui peut résulter dans le résultat ") </ / Code) est <code> SecurityException </code> (dans le thread actuel). * <p> * Le thread représenté par ce thread est obligé d'arrêter tout ce qu'il fait anormalement et de lancer un objet NOUVELLEMENT créé * <code> threaddeath </code> comme une exception. * <p> * Il est permis d'arrêter un thread qui n'a pas encore été démarré. <code> ThreadDeath </code> à moins qu'il ne doit effectuer une opération de nettoyage extraordinaire * (notez que le lancement de * <code> threadDeath </code> provoque <code> enfin </code> clauses de * <code> essayez </code> les instructions sont exécutées avant le thread * met officiellement en date). Si un <code> Catch </code> Clause attrape un objet * <code> threaddeath </code>, il est important de repenser l'objet * afin que le thread décède réellement. * <p> * Le gestionnaire d'erreurs supérieur qui réagit à des exceptions autrement non apprises * non apprivait le threadDeath </ Code>. Impossible de modifier ce thread. * @See #Interrupt () * @See #CheckAccess () * @See #Run () * @See #Start () * @SeE Threaddeath * @See ThreadGroup # Ungaughtexception (Thread, Thrownable) * @see SecurityManager # CheckAccess (Thread) * @see SecurityManager # CheckerMissionmate * @Depreteated That is Inhered Usefe. L'arrêt d'un fil avec * thread.stop le fait déverrouiller tous les moniteurs qu'il * a verrouillé (comme une conséquence naturelle de l'exception non contrôlée * <code> threaddeath </code> propageant la pile). Si * l'un des objets précédemment protégés par ces moniteurs était dans un état incohérent, les objets endommagés deviennent visibles pour * d'autres fils, entraînant potentiellement un comportement arbitraire. De nombreuses * utilisations de <code> stop </code> doivent être remplacées par du code qui modifie simplement une variable pour indiquer que le thread cible devrait * arrêter l'exécution. Le thread cible doit vérifier régulièrement cette variable * et revenir de sa méthode d'exécution de manière ordonnée * si la variable indique qu'il veut arrêter de fonctionner. Si le thread cible attend de longues périodes (sur une variable condition, * par exemple), la méthode <code> interruption </code> doit être utilisée pour * interrompre l'attente. Déprécié? </a>. * / @ DéprécatedPublic final void stop () {stop (new ThreadDeath ());}Comme commenté ci-dessus, les lignes 9 à 16 indiquent que la méthode stop () peut arrêter "d'autres threads". Le thread qui exécute la méthode thread.stop () est appelé le thread actuel, tandis que le "autre thread" est le thread représenté par le thread d'objet qui appelle la méthode thread.stop ().
comme:
public static void main (String [] args) {mythread thread = new mythread ... // .... thread.stop (); // ..}Dans la méthode principale, le thread actuel est le thread principal. Il s'exécute à la ligne 4 et souhaite arrêter le thread "autre thread". Cet autre thread est le thread représenté par l'objet de thread de la nouvelle classe Mythread.
Les lignes 21 à 23 indiquent qu'un fil qui n'a pas encore été démarré peut encore être arrêté. Son effet est: lorsque le fil démarre, il se termine immédiatement.
Les commentaires après la ligne 48 montrent profondément pourquoi la méthode stop () est obsolète! Pourquoi c'est peu sûr.
Par exemple, Threada Thread a des moniteurs responsables de la protection de certaines ressources critiques, telles que le montant des transferts bancaires. Lorsque le processus de transfert est en cours, le thread principal appelle la méthode threada.stop (). En conséquence, le moniteur est libéré et les ressources qu'elle protègent (la quantité de transfert) sont susceptibles d'être incohérentes. Par exemple, le compte A a diminué de 100, tandis que le compte B n'a pas augmenté de 100.
Deuxièmement, mécanisme d'interruption
Il y a trop de détails sur la façon d'utiliser correctement le mécanisme d'interruption en Java. Les méthodes interrompues () et ISinterrupted () reflètent si le thread actuel est dans un état interrompu.
① interrompu ()
/ *** teste si le thread actuel a été interrompu. L'état * <i> interrompu </i> du thread est effacé par cette méthode. En d'autres termes, si cette méthode devait être appelée deux fois successivement, le * deuxième appel retournerait faux (à moins que le thread actuel ne soit à nouveau interrompu, après que le premier appel ait effacé son statut d'interruption * et avant que le deuxième appel ne l'ait examiné). ** <p> Une interruption du thread est infligée à un thread car un thread n'était pas vivant * interrompu; * <code> false </code> sinon. * @see #isinterrupted () * @Revised. * / public static boolean interrupted () {return currentThread (). isInterrupted (true);}À partir des commentaires du code source, il teste l'état d'interruption du thread actuel, et cette méthode effacera l'état d'interruption.
②isterrupted ()
/ *** teste si ce fil a été interrompu. L'état <i> interrompu * </i> du thread n'est pas affecté par cette méthode. ** <p> Une interruption de thread ignorée parce qu'un thread n'était pas vivant * au moment de l'interruption sera reflété par cette méthode * Retour Faux. ** @return <code> True </ Code> Si ce thread a été interrompu; * <code> false </code> autrement. isInterrupted () {return isInterrupted (false);}Comme on peut le voir à partir des commentaires du code source, la méthode isInterrupted () n'effacera pas l'état d'interruption.
③Fiférence entre la méthode interrompue () et la méthode ISinterrupted ()
Comme on peut le voir à partir du code source, les deux méthodes sont appelées ISinterrupted (Boolean ClearInterrupted), sauf que celle avec le paramètre est vraie et l'autre avec le paramètre est fausse.
/ *** teste si un fil a été interrompu. L'état interrompu * est réinitialisé ou non sur la base de la valeur de Clear Interrupted qui est passé. * / Boolean natif privé est Interrupted (booléen ClearInterrupted);
Par conséquent, la première différence est que l'une efface le bit de l'interruption et l'autre n'efface pas le bit de l'interruption d'interruption.
Après avoir analysé le code source, vous pouvez voir la deuxième différence dans l'instruction de retour:
public static boolean interrupted () {return currentThread (). isInterrupted (true);} / ************************** / booléen public isInterrupted () {return isInterrupted (false);}Interrompu () teste l'état interrompu du thread actuel. Le iSinterrupted () teste le thread représenté par l'objet qui appelle la méthode. L'un est une méthode statique (il teste l'état d'interruption du thread actuel), et l'autre est une méthode d'instance (il teste l'état d'interruption du thread représenté par l'objet d'instance).
Ce qui suit est un exemple spécifique pour clarifier davantage cette différence.
Il y a une classe de thread personnalisée comme suit:
La classe publique Mythread étend Thread {@OverRidePublic void run () {super.run (); for (int i =; i <; i ++) {System.out.println ("i =" + (i +));}}}Examinons d'abord l'exemple de la méthode interrompue ():
classe publique run {public static void main (string [] args) {try {mythread thread = new Mythread (); thread.start (); thread.sleep (); thread.interrupt (); // thread.currentThread (). Interrupt (); System.out.println ("stop? =" + Thread.interrupted ()); // falSesystem.out.println ("stop? =" + Thread.interrupted ()); // FAUX MATIQUE n'est pas interrupté !!! // ...La ligne 5 démarre le fil de filetage et la ligne 6 fait dormir le thread principal pendant 1 seconde, de sorte que le fil de filetage a la possibilité d'obtenir l'exécution du processeur.
Une fois que le thread principal a dormi pendant 1, il reprend l'exécution à la ligne 7 et demande d'interrompre le fil de fil.
La ligne 9 teste si le fil est dans un état interrompu. Quel fil est testé ici? ? ? La réponse est le fil principal. parce que:
(1) interrompu () teste l'état d'interruption du thread actuel
(2) Le thread principal exécute l'instruction 9e ligne, donc le thread principal est le thread actuel
Regardons l'exemple de la méthode ISinterrupted ():
classe publique run {public static void main (string [] args) {try {mythread thread = new myThread (); thread.start (); thread.sleep (); thread.interrupt (); system.out.println ("est-ce qu'il est arrêté? =" + thread.isinterrupted ()); // true ("Sur la ligne 8, Isterrupted () Méthode appelée par l'objet thread. Par conséquent, l'état d'interruption du thread représenté par l'objet thread est testé. Étant donné que sur la ligne 7, le thread principal demande pour interrompre le thread, le résultat sur la ligne 8 est: vrai