Pourquoi invoquer Thread.currentThread.interrupt () dans un bloc catch InterruptException?

155

Pourquoi invoquer la méthode Thread.currentThread.interrupt()dans le bloc catch?

Hesey
la source

Réponses:

160

Ceci est fait pour garder l'état .

Lorsque vous attrapez le InterruptExceptionet l'avalez, vous empêchez essentiellement les méthodes / groupes de threads de niveau supérieur de remarquer l'interruption. Ce qui peut poser des problèmes.

En appelant Thread.currentThread().interrupt(), vous définissez l'indicateur d'interruption du thread, de sorte que les gestionnaires d'interruptions de niveau supérieur le remarqueront et pourront le gérer de manière appropriée.

Java Concurrency in Practice aborde ce sujet plus en détail au Chapitre 7.1.3: Répondre à une interruption . Sa règle est:

Seul le code qui implémente la politique d'interruption d'un thread peut avaler une demande d'interruption. Les tâches générales et le code de bibliothèque ne doivent jamais avaler les demandes d'interruption.

Péter Török
la source
15
Dans la documentation, il est indiqué que "Par convention, toute méthode qui se termine en lançant un InterruptedException statut d'interruption efface quand elle le fait. Je pense que cela rend la réponse plus claire en termes de pourquoi vous devez conserver l'état d'interruption.
Stelios Adamantidis
Il est également intéressant de noter que l' interrupt()appel est le seul moyen de définir l'indicateur d'interruption une fois que vous avez reçu une notification concernant cet état via l'autre «mécanisme de livraison» - le InterruptedExceptionet que vous souhaitez ou ne pouvez pas le relancer.
sevo
67

Je pense que cet exemple de code rend les choses un peu claires. La classe qui fait le travail:

   public class InterruptedSleepingThread extends Thread {

        @Override
        public void run() {
            doAPseudoHeavyWeightJob();
        }

        private void doAPseudoHeavyWeightJob() {
            for (int i=0;i<Integer.MAX_VALUE;i++) {
                //You are kidding me
                System.out.println(i + " " + i*2);
                //Let me sleep <evil grin>
                if(Thread.currentThread().isInterrupted()) {
                    System.out.println("Thread interrupted\n Exiting...");
                    break;
                }else {
                    sleepBabySleep();
                }
            }
        }

        /**
         *
         */
        protected void sleepBabySleep() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                //e.printStackTrace();
                Thread.currentThread().interrupt();
            }
        }
    }

La classe principale:

   public class InterruptedSleepingThreadMain {

        /**
         * @param args
         * @throws InterruptedException
         */
        public static void main(String[] args) throws InterruptedException {
            InterruptedSleepingThread thread = new InterruptedSleepingThread();
            thread.start();
            //Giving 10 seconds to finish the job.
            Thread.sleep(10000);
            //Let me interrupt
            thread.interrupt();
        }

    }

Essayez d'appeler l'interruption sans rétablir l'état.

Ajay George
la source
13
donc la conclusion est ??
Scott 混合 理论
3
Merci. Je vois ce que vous voulez dire maintenant: repl.it/@djangofan/InterruptedThreadExample
djangofan
20

Remarque:

http://download.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

Comment arrêter un thread qui attend pendant de longues périodes (par exemple, pour une entrée)?

Pour que cette technique fonctionne, il est essentiel que toute méthode qui intercepte une exception d'interruption et n'est pas prête à la traiter réaffirme immédiatement l'exception. Nous disons réaffirmer plutôt que renvoyer, car il n'est pas toujours possible de renvoyer l'exception. Si la méthode qui intercepte l'exception InterruptedException n'est pas déclarée pour lever cette exception (vérifiée), alors elle doit "se réinterrompre" avec l'incantation suivante:

Thread.currentThread().interrupt();

Cela garantit que le thread relèvera l'exception InterruptedException dès qu'il le pourra.

Bert F
la source
2

Je considérerais cela comme une mauvaise pratique ou au moins un peu risquée. Habituellement, les méthodes de niveau supérieur n'effectuent pas d'opérations de blocage et elles ne verront jamaisInterruptedException . Si vous le masquez à chaque endroit où vous effectuez une opération interruptible, vous ne l'obtiendrez jamais.

La seule justification pour Thread.currentThread.interrupt()et ne pas déclencher une autre exception ou une demande d'interruption de signalisation d'une autre manière (par exemple, définir interruptedune variable de variable locale dans la boucle principale d'un thread) est la situation où vous ne pouvez vraiment rien faire avec l'exception, comme dans les finallyblocs.

Voir la réponse de Péter Török, si vous voulez mieux comprendre les implications de l' Thread.currentThread.interrupt()appel.

Piotr Findeisen
la source
0

Se référer à la documentation java

Si ce thread est bloqué lors d'un appel de wait (), join (), sleep (long), son état d'interruption sera effacé et il recevra une InterruptedException.

Si ce thread est bloqué dans une opération d'E / S, l'état d'interruption du thread sera défini et le thread recevra une ClosedByInterruptException.

Si ce thread est bloqué dans un sélecteur, l'état d'interruption du thread sera défini et il reviendra immédiatement après l'opération de sélection.

Si aucune des conditions précédentes ne tient, l'état d'interruption de ce thread sera défini.

Donc, si vous changez la méthode sleepBabySleep () dans @Ajay George Answer to I / O operation ou juste un sysout, vous n'avez pas à redéfinir le statut pour arrêter le programme. (BTW, ils ne lancent même pas InterruptedException)

Tout comme @ Péter Török a dit => Ceci est fait pour garder l'état. (Et en particulier pour la méthode qui lancera InterruptedException)

Michael Ouyang
la source