La méthode $start()$ est utilisée pour démarrer un thread à ce moment, le thread est dans l'état ready (exécutable) et n'est pas en cours d'exécution une fois le $cpu. $ la tranche de temps est obtenue, commencez à exécuter la méthode $run()$. L'appel direct de la méthode $run()$ appelle uniquement une méthode dans une classe, qui est essentiellement exécutée dans le thread actuel. Par conséquent, cela ne peut être réalisé qu'en utilisant la méthode $start()$ pour appeler $run()$. Méthode véritable multithread.
@Slf4j(topic = "c.Test4") public class Test4 { public static void main(String[] args) { Thread t1 = new Thread("t1"){ @Override public void run() { log.debug("running"); } }; t1.run(); } }
Le code ci-dessus est la méthode $run()$ qui est appelée directement. Vous pouvez voir dans les informations imprimées que le thread $main$ a exécuté cette méthode.
@Slf4j(topic = "c.Test4") public class Test4 { public static void main(String[] args) { Thread t1 = new Thread("t1"){ @Override public void run() { log.debug("running"); } }; t1.start(); } }
Et si vous utilisez la méthode $start()$ pour démarrer, c'est la vraie méthode $run$ exécutée par le thread $t1$.
Il convient de noter que lorsque l'objet $Thread$ appelle la méthode $start()$, il entrera dans l'état prêt. Lorsqu'il est dans l'état prêt, la méthode $start()$ ne peut pas être appelée. , sinon il lancera une exception $IllegalThreadStateException$, comme indiqué dans le code suivant
@Slf4j(topic = "c.Test4") public class Test4 { public static void main(String[] args) { Thread t1 = new Thread("t1"){ @Override public void run() { log.debug("running"); } }; t1.start(); t1.start(); } }
Informations sur l'exception :
L'appel de la méthode $sleep()$ sera fait passer le thread actuel de l'état $Running$ à l'état $Time Waiting$ (bloqué)
D'autres threads peuvent utiliser la méthode $interrupt$ pour interrompre le thread en veille. À ce moment, la méthode $sleep$ le fera. throw InterruptedException
Le fil après la mise en veille peut ne pas être exécuté immédiatement
Il est recommandé d'utiliser le $sleep$ de $TimeUnit$ au lieu du $sleep$ de $Thread$ pour obtenir une meilleure lisibilité. Exemple de code
@Slf4j(topic = "c.Test5") public class Test5 { public static void main(String[] args) { Thread t1 = new Thread("t1"){ @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }; t1.start(); log.debug("t1 state {}", t1.getState()); //让主线程休眠500ms try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } log.debug("t1 state {}", t1.getState()); } } //17:13:21.729 [main] DEBUG c.Test5 - t1 state RUNNABLE //17:13:22.245 [main] DEBUG c.Test5 - t1 state TIMED_WAITING
Dans le code ci-dessus, le thread $t1$ est démarré en premier. À ce stade, l'état du thread d'impression doit être dans l'état $RUNNABLE$, et laisser le thread principal dormir empêche le thread principal d'exécuter l'impression en premier. , mais n'est pas encore entré dans l'état $sleep()$. Lorsque la méthode $sleep$ dans $run()$ est exécutée, le thread entre dans l'état $TIMED WAITING$
@Slf4j(topic = "c.Test6") public class Thread6 { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread("t1") { @Override public void run() { try { log.debug("enter sleep"); Thread.sleep(2000); } catch (InterruptedException e) { log.debug("wake up"); e.printStackTrace(); } } }; t1.start(); Thread.sleep(1000); log.debug("interrupt t1"); //被唤醒 t1.interrupt(); } }
Résultats de l'exécution
Dans le code ci-dessus, lorsque la méthode $start$ est démarrée, $t1$ Le thread entre en état de veille, imprime les informations d'invite et le temps de veille est de $2s$ Après avoir dormi $1s$ dans le thread $main$, il interrompt la veille du thread $t1$ et provoque l'interruption. informations et appelle la méthode $interrupt()$. À ce stade, le thread est interrompu et une exception est levée.
La classe $TimeUnit$ a ajouté une nouvelle unité dans laquelle dormir, qui est plus lisible, mais fondamentalement, il n'y a aucune différence. C'est juste une conversion d'unité
TimeUnit.SECONDS.sleep(1);//该语句作用是睡眠一秒
Appeler $yield$ fera le. processus actuel Entrez l'état prêt $Runnable$ à partir de $Running$, puis planifiez et exécutez d'autres threads. L'implémentation spécifique dépend du planificateur de tâches du système d'exploitation (c'est-à-dire lorsqu'il n'y a pas d'autres tâches dans le planificateur de tâches, même s'il n'y a pas d'autres tâches dans le planificateur de tâches). si $cpu$ est abandonné, continuez à exécuter le thread) $sleep$ entrera dans l'état de blocage après l'exécution. Si le temps de veille ne se termine pas à ce moment, $cpu$ ne sera pas alloué au thread, mais $yield. $ entrera dans l'état prêt, c'est-à-dire que si aucun autre thread n'a besoin d'être exécuté, le thread se verra également attribuer une tranche de temps, ce qui constitue la plus grande différence entre $sleep$ et $yield$ Priorité du thread
demandera au planificateur de donner la priorité à la planification du thread, mais ce n'est qu'une invite, le planificateur peut l'ignorer
Si $cpu$ est occupé, alors celui avec la priorité la plus élevée obtiendra plus de tranches de temps, mais lorsque $cpu$ l'est inactif, la priorité sera presque nulle
sans Lorsque vous utilisez $cpu$ pour calculer, ne laissez pas $while(true)$ inactif et gaspillez $cpu$. temps, vous pouvez utiliser $yield$ ou $sleep$ pour confier l'utilisation de $cpu$ à d'autres programmes
while (true) { try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } }
Oui Utilisez $wait$ ou des variables de condition pour obtenir des effets similaires
La différence est que les deux derniers nécessitent un verrouillage et les opérations de réveil correspondantes, qui conviennent généralement aux scénarios nécessitant une synchronisation
$sleep$ conviennent aux scénarios qui ne nécessitent pas de synchronisation de verrouillage
Les résultats d'impression du programme suivant :
@Slf4j(topic = "c.Test6") public class Test6 { static int r = 0; public static void main(String[] args) { test(); } private static void test() { log.debug("开始"); Thread t = new Thread("t1") { @Override public void run() { log.debug("开始"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } log.debug("结束"); r = 10; } }; t.start(); log.debug("r的值是{}", r); log.debug("结束"); } }
Étant donné que le thread principal et le thread $t1$ sont parallèles, le thread $t1$ a besoin de $1s$ pour calculer la valeur de $r$, et le thread principal imprimera la valeur de $r$ au début, donc la valeur imprimée est 0
Solution :
Ajoutez $t.join();$ après $t.start();$ c'est Can. La fonction de $join$ est d'attendre qu'un thread termine son exécution.
Du point de vue de l'appelant, si vous devez attendre le résultat avant de poursuivre l'exécution, c'est synchrone, et si vous n'avez pas besoin d'attendre le résultat renvoyé pour continuer l'exécution, c'est asynchrone.
Donc la méthode $join$ permet en fait de l'exécuter de manière synchrone
$join(milliseconds)$La méthode peut avoir un paramètre à passer dans le temps d'attente si le temps d'exécution du thread est plus long. que le temps d'attente, une fois le temps d'attente écoulé, il cessera d'attendre. Si le temps d'exécution du thread est inférieur au temps d'attente, l'attente se terminera une fois l'exécution du thread terminée. Le temps d'attente réglé n'expirera pas.
打断$sleep, wait, join$的线程,即打断阻塞状态的线程
打断$sleep$的线程,会清空打断状态
@Slf4j(topic = "c.Test7") public class Test7 { public static void main(String[] args) throws InterruptedException { Thread t = new Thread("t1"){ @Override public void run() { log.debug("sleep..."); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } }; t.start(); Thread.sleep(1000); log.debug("interrupt"); t.interrupt(); log.debug("打断标记: {}", t.isInterrupted()); } }
因此我们可以在线程中判断打断标记,来决定是否被打断,以及执行被打断之前的收尾工作。
@Slf4j(topic = "c.Test8") public class Test8 { public static void main(String[] args) throws InterruptedException { Thread t = new Thread("t1"){ @Override public void run() { while (true) { if (Thread.currentThread().isInterrupted()) { log.debug("线程被打断了"); break; } } } }; t.start(); Thread.sleep(1000); log.debug("interrupt"); t.interrupt(); } }
默认情况下,$java$需要等待所有线程都运行结束,才会结束。有一种特殊的线程叫做守护线程,只要其他非守护线程运行结束了,即使守护线程的代码没有执行完毕,也会强制结束。
@Slf4j(topic = "c.Test10") public class Test10 { public static void main(String[] args) throws InterruptedException { Thread t = new Thread("t1") { @Override public void run() { while (true) { } } }; //设置线程为守护线程 t.setDaemon(true); t.start(); Thread.sleep(1000); log.debug("主线程结束"); } }
如果不把$t$设置为守护线程,则因为线程内部的死循环,导致程序不会结束运行。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!