- L'interruption de thread
Un thread en cours d'exécution peut-il être contrôlé par un autre thread besides les interruptions normales de tranche de temps ? En d'autres termes, un autre thread peut-il forcer un thread spécifique à céder le CPU ou terminer son exécution prématurément ? En dehors des mécanismes de synchronisation, il existe deux approches :
Première approche (à éviter) : Les méthodes Thread.stop(), Thread.suspend(), Thread.resume() et Runtime.runFinalizersOnExit(). Ces méthodes sont obsolètes et leur utilisation est extrêmement dangereuse.
Seconde approche (recommandée) : La méthode Thread.interrupt(). Cependant, son fonctionnement doit être bien compris.
1.1 Impossible d'interrompre un thread en cours d'exécution
Examinons le code suivant :
public class DemonstrationThread { public static void main(String[] args) { Runnable cible = new ProcesseurTache(); Thread worker = new Thread(cible); worker.start(); worker.interrupt(); } }
</div>**Résultat :** Le message "Le thread s'exécute..." s'affiche une fois par seconde. Le programme ne montre aucun signe dtermination.
Ce code démontre que `interrupt()` n'interrompt pas un thread en cours d'exécution actifs et ne le force pas à céder le CPU. Alors, que signifie exactement "interrompre" ?
Examinons ce que fait `interrupt()` : lorsqu'on appelle `worker.interrupt()`, le flag d'interruption (interrupted status) du thread est positionné. Ce statut booléen peut être vérifié via `Thread.currentThread().isInterrupted()`.
### 1.2 Vérification du statut d'interruption
Voici le modèle classique d'utilisation de l'interruption :
<div>```
@Override
public void run() {
try {
while (!Thread.currentThread().isInterrupted() && resteDuTravail) {
// traitement à effectuer
}
} catch (InterruptedException e) {
// le thread a été interrompu pendant un sleep ou wait
} finally {
// opérations de nettoyage
}
}
1.3 Interruption d'un thread bloqué
Lorsque le thread est bloqué (par Object.wait(), Thread.join() ou Thread.sleep()), l'appel à interrupt() provoque immédiatement une InterruptedException car un thread qui ne s'exécute pas ne peut pas vérifier son propre flag.
public class Demonstration2 { public static void main(String[] args) { Runnable task = new TacheDifferee(); Thread worker = new Thread(task); worker.start();
while (true) {
worker.interrupt();
}
}
} /* Результат: java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at TacheDifferee.run(Demonstration2.java:4) at java.lang.Thread.run(Unknown Source)*/
</div>2. Différences entre sleep et wait
----------------------------------
### 2.1 Origine des méthodes
Ces deux méthodes proviennent de classes différentes : `sleep()` appartient à `Thread`, tandis que `wait()` appartient à `Object`.
### 2.2 Gestion des verrous
La différence principale réside dans la gestion des verrous : la méthode `sleep()` ne libère pas les verrous détenus par le thread, whereas `wait()` libère tous les verrous, permettant à d'autres threads d'utiliser les blocs synchronisés ou les méthodes synchronisées.
### 2.3 Conditions d'utilisation
Les méthodes `wait()`, `notify()` et `notifyAll()` ne peuvent être utilisées que dans les méthodes synchronisées (mot-clé `synchronized`) ou dans les blocs synchronisés. En revanche, `sleep()` peut être appelée n'importe où.
### 2.4 Comportement détaillé
Lorsqu'un thread appelle `sleep()`, il conserve tous les verrous d'objets qu'il détenus, donc les autres threads restent bloqués. Pendant le `sleep`, si un autre thread appelle `interrupt()` sur ce thread, une `InterruptedException` est levée. Si cette exception n'est pas capturée, le thread se termine définitivement (état TERMINATED). Si elle est capturée, le programme continue dans le bloc `catch` (et éventuellement `finally`).
Pour la méthode `wait()`, le thread doit être réveillé explicitement par `notify()` ou `notifyAll()`. Lorsqu'un thread appelle `wait()` et possède des verrous sur certains objets, il libère tous ces verrous (pas seulement celui sur lequel `wait()` a été appelé), permettant ainsi à d'autres threads d'accéder aux données synchronisées. Comme pour `sleep()`, `wait()` peut être interrompu par `interrupt()` et générer une `InterruptedException` avec le même comportement.
### 2.5 Alternative pour un sleep sans interruption
Il est posssible d'utiliser la bibliothèque Guava pour effectuer un sleep sans levée d'interruption :
<div>```
Uninterruptibles.sleepUninterruptibly(100, TimeUnit.MILLISECONDS);