|
Dans ce tips nous allons voir comment gérer de manière correcte l'exception InterruptedException.
Dans le cas d'utilisation de Thread il est souvent utile de pouvoir stopper l'exécution d'un Thread.
Les méthodes stop, start et suspend étant deprecated, la javadoc conseille d'utiliser un boolean pour indiquer si le Thread doit continuer à s'exÈcuter.
En fait la classe Thread contient déjà une variable (accessible via la méthode isInterrupted()) indiquant si le Thread doit s'interrompre.
La méthode interrupt() permet d'interrompre un Thread.
La classe TestThread1 illustre ce comportement.
public class TestThread1 implements Runnable {
public void run() {
while(Thread.currentThread().isInterrupted() == false) {
System.out.println("dans la boucle");
//on simule une courte pause
for(int k=0; k<100000000; k++);
System.out.println("Thread isInterrupted = " + Thread.currentThread().isInterrupted());
}
}
public static void main(String[] args) {
Thread t = new Thread(new TestThread1());
t.start();
//on laisse le temps à l'autre Thread de se lancer
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
System.out.println("interruption du thread");
t.interrupt();
}
}
L'exécution de cette classe donne quelque chose du genre:
dans la boucle
Thread isInterrupted = false
dans la boucle
interruption du thread
Thread isInterrupted = true
Jusqu'ici ça marche très bien, mais les choses se compliquent lorsque l'on interrompt un Thread qui est en train d'exécuter une méthode bloquante tel que:
- join et sleep de la classe Thread,
- wait de la classe Object.
Dans ce cas la méthode interrupt ne va pas interrompre le Thread ( isInterrupted() retourne false) mais provoquer l'exception InterruptedException dans le Thread que l'on essaye de stopper.
Voici un exemple:
public class TestThread2 implements Runnable {
public void run() {
while(Thread.currentThread().isInterrupted() == false) {
System.out.println("sleep");
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
System.out.println("Dans l'exception, Thread isInterrupted = " + Thread.currentThread().isInterrupted());
}
System.out.println("Thread isInterrupted = " + Thread.currentThread().isInterrupted());
}
}
public static void main(String[] args) {
Thread t = new Thread(new TestThread2());
t.start();
try {
Thread.sleep(2000);
} catch(InterruptedException e) {}
System.out.println("interruption du thread");
t.interrupt();
}
}
L'exécution de cette classe produit l'affichage suivant:
sleep
Thread isInterrupted = false
sleep
interruption du thread
Dans l'exception, Thread isInterrupted = false
Thread isInterrupted = false
sleep
Thread isInterrupted = false
sleep
...
Et là le programme va se mettre à boucler indéfiniment.
Ici on voit bien que le Thread ne s'est pas interromput correctement.
C'est pour cela que lorsqu'on catche une InterruptedException il faut réinterrompre le Thread en appelant de nouveau la méthode interrupt().
Dans le catch de InterruptedException il faut mettre:
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
System.out.println("Dans l'exception, Thread isInterrupted = " + Thread.currentThread().isInterrupted());
//Ici on interrompt de nouveau le Thread
Thread.currentThread().interrupt();
System.out.println("Apres la deuxieme interruption, Thread isInterrupted = " + Thread.currentThread().isInterrupted());
}
Si on relance TestThread2 avec cette modification on obtient:
sleep
interruption du thread
Dans l'exception, Thread isInterrupted = false
Apres la deuxieme interruption, Thread isInterrupted = true
Et le programme se termine correctement.
En résumé, il ne faut pas oublier de réinterrompre un Thread lorsque l'on catche une InterruptedException.
Si vous voulez plus d'infomations sur ce fonctionnement vous pouvez regarder la javadoc de la classe Thread.
|