English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Analyse de la mécanique d'interruption des threads Java

Le mécanisme d'interruption des threads fournit une méthode pour réveiller un thread de l'attente bloquée, tente de rompre le processus en cours du thread cible pour qu'il réponde à une nouvelle commande. Java laisse cette liberté aux développeurs, nous devrions l'utiliser bien.
Aujourd'hui, parlons du mécanisme d'interruption des threads Java.

Le mécanisme d'interruption des threads fournit une méthode, qui a deux utilisations courantes :

Réveiller le thread de l'attente bloquée et effectuer un traitement de 'interruption contrôlée' en conséquence.
Essayer d'informer le thread cible : interrompez le processus en cours, répondez à une nouvelle commande.
Par exemple, pour la première utilisation, voyons le code suivant :

synchronisé (lock) {
  essayer {
    while (!check()) {
      lock.wait(1000);
    }
  }
    e.printStackTrace();
  }
}

Ce code utilise wait fourni par Java/Le mécanisme notify, lorsque le thread exécute lock.wait(), se bloquera, il y a trois cas qui permettent au thread de reprendre son exécution.

1、dépassement du délai 1000ms terminé, exécute normalement la prochaine ligne de code.

2、un autre thread exécute le code suivant pour se réveiller activement

synchronisé (lock) {
  lock.notifyAll(); // ou lock.notify();
}

Cela s'exécute également normalement pour la prochaine ligne de code.

3、un autre thread demande d'intervenir sur le thread en attente

// Obtenir une référence au thread en attente
Thread a;
a.interrupt();

Le thread 'interruption' a, lève une exception InterruptedException à l'endroit de lock.wait().

En résumé, vous pouvez penser que object.wait() fait ces choses internes :

boolean checkTimeout = timeout > 0;
Thread current = Thread.currentThread();
lock.addWaiter(current);
while (!current.isNotified()) {
  if (current.isInterrupted()) {
    current.clearInterrupted();
    throw new InterruptedException();
  }
  if (checkTimeout) {
    if (timeout == 0) break;
    timeout--;
  }
}

Ce n'est pas tout à fait exact, car wait n'utilise pas ce type de "polling actif" pour les vérifications, mais la logique de jugement sur les drapeaux est correcte.

Commençons par explorer l'opération mentionnée précédemment : "interruption manuelle"

// sun.nio.ch.Interruptible
public interface Interruptible {
  void interrupt(Thread var1);
}
// java.lang.Thread
private volatile Interruptible blocker;
private final Object blockerLock = new Object();
public void interrupt() {
  if (this != Thread.currentThread())
    checkAccess();
  synchronized (blockerLock) {
    Interruptible b = blocker;
    if (b != null) {
      interrupt0();
      b.interrupt(this);
      return;
    }
  }
  interrupt0();
}
// Juste pour définir le drapeau d'interruption
private native void interrupt0();

Il est possible de voir que thread.interrupt() vérifie d'abord les permissions, puis appelle effectivement interrupt0() pour définir le drapeau d'interruption du thread, et si le thread courant a l'Interruptible de nio, il appelle également sa fonction de rappel.

Attention, interrupt0() ne fait que définir le drapeau d'interruption du thread.

Qu'arrive-t-il lorsqu'un thread n'est pas bloqué, n'est pas dans des zones telles que object.wait(), thread.join(), Thread.sleep() qui ne sont pas contrôlées par la logique du programme Java ? La réponse est qu'aucune chose ne se passe, si le thread est interrompu ou non, cela ne peut être déterminé que par la vérification proactive du drapeau d'interruption.

Comment vérifier ? Thread expose deux interfaces, Thread.interrupted() et thread.isInterrupted().

// java.lang.Thread
public static boolean interrupted() {
  return currentThread().isInterrupted(true);
}
public boolean isInterrupted() {
  return isInterrupted(false);
}
private native boolean isInterrupted(boolean clearInterrupted);

On peut voir que les deux dépendent de isInterrupted(boolean), qui retourne si le thread a été interrompu et qui efface le drapeau d'interruption selon les besoins.

Lorsqu'un appel de fonction peut se bloquer, les fonctions de bibliothèque Java marquent le point de blocage avec throws InterruptedException et exigent que vous écriviez un try catch pour gérer l'interruption.

Lorsque un thread se bloque, comme mentionné précédemment, Java vérifie le drapeau d'interruption, le supprime puis lève InterruptedException.

// java.lang.Object
public final void wait() throws InterruptedException {
  wait(0);
}
public final native void wait(long timeout) throws InterruptedException;

Si un thread reçoit InterruptedException et continue à exécuter du code bloquant après cela, il continuera à se bloquer comme si de rien n'était. Car Java efface le drapeau d'interruption à l'intérieur !

Nous écrivons couramment les trois types de codes suivants pour gérer InterruptedException :

transmettez InterruptedException au niveau supérieur.

public void foo() throws InterruptedException {
  synchronisé (lock) {
    lock.wait();
  }
}

Réinitialisez le signe d'interruption en cas de InterruptedException.

essayer {
  synchronisé (lock) { 
    lock.wait(); 
  } 
} 
  Thread.currentThread().interrupt();
  //break; 
}

Terminez d'abord, puis relancez InterruptedException.

public void bar() throws InterruptedException {
  InterruptedException ie = null;
  boolean done = false;
  tandis que (!done) {
    synchronisé (lock) {
      essayer {
        lock.wait();
      }
        ie = e;
        continue;
      }
    }
    done = true;
  }
  si (ie != null) {
    lancer ie;
  }
}

Si un thread ignore le signe d'interruption et InterruptedException, il peut toujours bien fonctionner. Mais cela va à l'encontre de notre intention d' concevoir des threads multiples, nous souhaitons que les threads collaborent harmonieusement et de manière ordonnée pour réaliser des fonctions spécifiques. Par conséquent, le thread contrôlé doit répondre à l'interruption. Java laisse ce pouvoir aux développeurs, nous devons l'utiliser correctement.

Voici l'intégralité des connaissances sur le mécanisme d'interruption des threads Java que nous avons présentées cette fois. Si vous avez des questions, vous pouvez discuter dans la zone de commentaires ci-dessous. Merci du soutien à la tutorial de cri.

Déclaration : Le contenu de cet article est issu du réseau, propriété de ses auteurs respectifs, contribué et téléversé par les utilisateurs d'Internet de manière spontanée. Ce site n'en possède pas la propriété, n'a pas fait l'objet d'une rédaction humaine et n'assume aucune responsabilité juridique connexe. Si vous trouvez du contenu suspect de violation de droits d'auteur, veuillez envoyer un e-mail à : notice#oldtoolbag.com (veuillez remplacer # par @ lors de l'envoi d'un e-mail pour signaler une violation de droits d'auteur, et fournissez des preuves pertinentes. Une fois vérifié, ce site supprimera immédiatement le contenu suspect de violation de droits d'auteur.

Vous pourriez aussi aimer