Parler d'interruption de fil en Java

Pilaf 1990 2022-07-23 17:46:35 阅读数:256

parlerinterruptionfilenjava

JavaThread in Runtime,Y a - t - il un moyen de l'arrêter??InJDKDeThreadDans la classestopEtdestroyMéthodes,Mais a été marqué obsolète,stopLa méthode n'est pas recommandée parce qu'elle n'est pas sûre,Par exemple, il permet au Thread de libérer la serrure qu'il tient,Cela peut entraîner un état incohérent des ressources qu'il protège.,destroyLa méthode est lancée directementNoSuchMethodErrorAnomalie.

C'est vrai、Une façon élégante d'interrompre un thread est d'envoyer un signal d'interruption au thread(Qui appelle l'Instance threadinterruptMéthodes,Pour reprendre les mots de Yu Chunlong.,interruptCe mot est facilement trompeur,Au sens littéral, c'est comme si le thread s'était arrêté à mi - chemin.,En fait, non.,Appeler l'Instance threadinterruptMéthodes,Juste un signal d'interruption au fil,Si le signal d'interruption est lancéInterruptedExceptionPour voir si le fil est légèrement bloqué,L'état de blocage léger est expliqué ci - dessous.),Le thread gère ensuite correctement le signal d'interruption;Ou le thread vérifie lui - même un drapeau de terminaison(Comme unvolatileDebooleanValeur)Pour décider s'il faut arrêter.

Laissez le thread vérifierbooleanConditions pour une sortie élégante

Insérer la description de l'image ici

package thread;
/** * @author pilaf * @description * @date 2022-05-04 14:41 **/
public class ThreadExitDemo {

private static volatile boolean closeFlag = false;
public static void main(String[] args) throws Exception{

Thread thread = new Thread(() -> {

while (!closeFlag) {

try {

// Simuler les tâches nécessitant un traitement cyclique , Comme continuer à extraire des données de la base de données pour le traitement 
Thread.sleep(1000);
System.out.println("thread is running");
} catch (InterruptedException e) {

e.printStackTrace();
}
}
System.out.println("thread will be closed");
});
thread.start();
Thread.sleep(3000);
closeFlag = true;
}
}

Il y a un défaut dans cette approche , C'est - à - dire, s'il n'y a pas de logique à gérer dans une boucle , Il n'y a aucun moyen de vérifier à plusieurs reprises si le fil doit être arrêté .À ce moment - là., Le mécanisme d'interruption du fil est nécessaire .

En appelant le threadinterruptMéthode d'interruption du fil

Insérer la description de l'image ici

package thread;
/** * @author pilaf * @description * @date 2022-05-04 14:51 **/
public class ThreadInterruptDemo {

public static void main(String[] args) {

Object lock = new Object();
Thread thread = new Thread(()->{

synchronized (lock) {

try {

lock.wait();
} catch (InterruptedException e) {

System.out.println("thread is interrupted");
e.printStackTrace();
}
}
});
thread.start();
System.out.println("interrupt thread");
// Si vous n'appelez pasinterrupt,ThreadthreadÇa va rester bloqué.waitMéthodes, À moins qu'il n'y ait un appel de thread lockDenotifyRéveille - toi.
thread.interrupt();
}
}

Par appelThreadDeinterruptMéthodes, Peut envoyer un signal d'interruption au fil . Quand un signal d'interruption est envoyé au fil , Le thread est dans un état différent , Le comportement est différent , Lorsque le thread est WAITINGOuTIMED_WAITINGDans l'état,Va lancerInterruptedException, Et se réveillera ( Dans l'exemple ci - dessus, c'est par interruptJeanthreadDewaitRéveille - toi.); Si le thread est dans BLOCKED L'état ne lance pas InterruptedException; Si le thread est en cours d'exécution , Et ne lance pas d'exception d'interruption , Mais il est possible de déterminer si le thread a reçu un signal d'interruption en vérifiant son état d'interruption .

Quelles méthodes sont lancées lorsque le fil est interrompu InterruptedException?

Thread.sleep()、Thread.join()、Object.wait() Attendez sur la signature de la méthode throws InterruptedException La méthode lance une exception d'interruption lorsqu'elle est interrompue . Ces appels de méthode permettent au thread d'entrer dans WAITINGOuTIMED_WAITINGStatut,Ces états sont Blocage léger .

Peut être interrompusynchronized Bloc de code? ?

La réponse est non.,Comme suit, Le programme sera toujours en cours d'exécution ,Appeléinterrupt Impossible d'interrompre le thread . Vous ne pouvez attendre que le thread finisse lui - même .
Insérer la description de l'image ici

package thread;
/** * @author pilaf * @description * @date 2022-05-04 15:17 **/
public class SynchronizedInterruptDemo {

private static volatile boolean flag = true;
public static void main(String[] args) {

Object lock = new Object();
Thread thread = new Thread(()->{

synchronized (lock) {

while (flag) {

int a = 1;
a++;
}
}
System.out.println("after synchronized block");
});
thread.start();
thread.interrupt();
}
}

À ce moment - là, il est possible de sortir de la boucle en vérifiant par le thread lui - même s'il a reçu une interruption .

Le thread vérifie lui - même s'il a reçu un signal d'interruption

Dans l'exemple ci - dessus,,AjouterThread.interruptedVérifiez, On peut déterminer si le thread a reçu une demande d'interruption , Si reçu , Le thread peut sauter de la boucle lui - même , L'élégance se termine .
Insérer la description de l'image ici

package thread;
/** * @author pilaf * @description * @date 2022-05-04 15:17 **/
public class SynchronizedInterruptDemo {

private static volatile boolean flag = true;
public static void main(String[] args) {

Object lock = new Object();
Thread thread = new Thread(()->{

synchronized (lock) {

while (flag) {

int a = 1;
a++;
if (Thread.interrupted()) {

break;
}
}
}
System.out.println("after synchronized block");
});
thread.start();
thread.interrupt();
}
}

ThreadDansisInterruptedMéthodes etinterruptedDifférence de méthode

Thread Il y a une méthode statique dans la classe interruptedIl y a une autre méthode d'instanceisInterrupted, Le premier efface l'état d'interruption après avoir lu l'état d'interruption actuel du fil ,Non répétable, Ce dernier ne s'efface pas après avoir lu l'état d'interruption ,Peut être lu à plusieurs reprises.

Une fosse commune à l'état perturbé

Quand le fil est légèrement bloqué , Quand un signal d'interruption est envoyé au fil , Le thread a été lancé à l'intérieur InterruptedExceptionAprès, Relisez l'état d'interruption du fil , Vous constaterez que l'état n'est pas interrompu . En fait, l'état d'interruption et l'exception d'interruption sont la façon dont le code interne du thread perçoit s'il reçoit un signal d'interruption , Si vous donnez une exception d'interruption, vous ne donnez pas l'état d'interruption , Si l'état d'interruption est donné, l'exception d'interruption n'est pas donnée .
Insérer la description de l'image ici

package thread;
/** * @author pilaf * @description * @date 2022-05-04 15:40 **/
public class InterruptedExceptionDemo {

public static void main(String[] args) throws Exception{

Thread thread = new Thread(()->{

while (true) {

if (Thread.interrupted()) {

break;
}
try {

Thread.sleep(1000);
} catch (InterruptedException e) {

System.out.println(" Si le thread actuel est interrompu :"+ Thread.interrupted());
e.printStackTrace();
}
}
});
thread.start();
//Pour démontrer l'effet, J'ai dormi ici exprès 100MS, Pour que le signal d'interruption soit sleep Lancer dans une situation anormale ,Pas directement.break
Thread.sleep(100);
thread.interrupt();
}
}

Convertir l'exception d'interruption en état d'interruption , Pour que le signal d'interruption puisse être détecté à temps :
Insérer la description de l'image ici

package thread;
/** * @author pilaf * @description * @date 2022-05-04 15:40 **/
public class InterruptedExceptionDemo {

public static void main(String[] args) throws Exception{

Thread thread = new Thread(()->{

while (true) {

if (Thread.interrupted()) {

break;
}
try {

Thread.sleep(1000);
} catch (InterruptedException e) {

System.out.println(" Si le thread actuel est interrompu :"+ Thread.interrupted());
// Convertir l'exception d'interruption en état d'interruption ,Comme ça.if L'interruption peut être détectée 
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
});
thread.start();
//Pour démontrer l'effet, J'ai dormi ici exprès 100MS, Pour que le signal d'interruption soit sleep Lancer dans une situation anormale ,Pas directement.break
Thread.sleep(100);
thread.interrupt();
}
}

Un exemple qui pourrait ne pas correspondre à votre perception

C'est bon,java Les interruptions de fil sont presque terminées , Voici un exemple de consolidation .

package thread;
import java.time.LocalDateTime;
/** * @author pilaf * @description * @date 2022-05-04 15:55 **/
public class WaitTest {

public static void main(String[] args) throws Exception{

Object lock = new Object();
Thread t1 = new Thread(()->{

synchronized (lock) {

try {

lock.wait();
} catch (InterruptedException e) {

// Déclarations de sortie2
System.out.println("catch InterruptedException at: " + LocalDateTime.now());
}
}
});
Thread t2 = new Thread(()->{

synchronized (lock){

try {

//Sommeil5Secondes
Thread.sleep(5000);
} catch (InterruptedException e) {

e.printStackTrace();
}
}
});
t1.start();
//Pour s'assurert2Int1Après le démarrage, Dors un peu. 
Thread.sleep(100);
t2.start();
// Déclarations de sortie1
System.out.println("interrupt t1 at: " + LocalDateTime.now());
t1.interrupt();
}
}

Après l'exécution du programme ci - dessus ,Déclarations de sortie2 Temps d'impression et déclarations de sortie 1 Combien de temps entre les temps d'impression ?
La réponse est:5Secondes.
Insérer la description de l'image ici
Parce quelock.wait()- Oui.t1 Le fil entre dans un état de blocage Léger (WAITINGStatut),wait- Oui.t1Relâchez la serrure.lock,Et puist2 Le fil l'a. lockVerrouillage,Sommeil5Secondes,Int2ThreadstartAprès, Le fil principal donne t1 Le fil a envoyé un signal d'interruption ,À ce moment - là.t1 Le fil est réveillé ( Un autre réveil t1 La façon dont le thread appelle notifyMéthodes),Maist2Sommeil du fil5 La seconde n'est pas finie. ,t1 Même quand on se réveille, on attend d'avoir lock Après la serrure, l'exécution peut commencer lock.wait()Code après appel,Attendez.t2Sommeil5Après quelques secondes,t1Prends ça.lockVerrouillage,Se retrouver dansWAITING J'ai reçu un signal d'interruption , Alors lancez un InterruptedException.


Références:
1. Yu Chunlong 《JavaPrincipe de mise en œuvre simultanée JDKAnalyse du code source》
2. Yin Wenjie 《Java Haute concurrence et cadre de collecte JCFEtJUC Analyse et mise en oeuvre du code source 》

Copyright:Cet article est[Pilaf 1990]Établi,Veuillez apporter le lien original pour réimprimer,remercier。 https://fra.fheadline.com/2022/204/202207231505092861.html