Interruption de threads Java et méthodes sleep et wait

  1. 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);

Étiquettes: Java Concurrence Threads synchronisation Thread

Publié le 5 juillet à 21h01