Maison  >  Article  >  Java  >  Quels sont les 6 états et cycles de vie des threads Java ?

Quels sont les 6 états et cycles de vie des threads Java ?

王林
王林avant
2023-05-02 12:07:061418parcourir

    1. État du thread (cycle de vie)

    Un thread ne peut être que dans un seul état à un moment donné.

    Les threads peuvent avoir les 6 états suivants :

    • Nouveau (nouvellement créé) : thread non démarré ;

    • Runnable (exécutable) : thread exécutable qui doit attendre les ressources du système d'exploitation ;

    • Bloqué : un thread bloqué en attendant le verrouillage du moniteur

    • Attente : attente de l'état de réveil, attente indéfinie qu'un autre thread se réveille

    • Attente temporisée : dans Un thread qui attend qu'un autre thread effectue un ; opération dans le délai d'attente spécifié ;

    • Terended (terminé) : un fil de discussion qui s'est terminé.

    Pour déterminer l'état actuel d'un thread, vous pouvez appeler la méthode getState

    Diagramme de relation entre l'état du thread

    Remarque : L'état de la boîte en pointillés (toutes les lettres majuscules en anglais) est l'état du thread Java.

    Quels sont les 6 états et cycles de vie des threads Java ?

    2. Statut du fil d'opération

    2.1. Nouveau statut de création (NOUVEAU)

    est le statut du fil qui n'a pas été démarré une fois l'instanciation terminée.

    Les threads peuvent être créés de trois manières

    • Remplacer la méthode run() de la classe Thread

    • Implémenter l'interface Runnable

    • Implémenter l'interface Callable

    Un exemple simple résume les trois façons

    public class Demo {
    
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            /**
             * 1.直接重写run() 或继承Thread类再重写run()
             */
            Thread thread = new Thread() {
                @Override
                public void run() {
                    System.out.println("Thread");
                }
            };
            // 开启线程
            thread.start();
    
            /**
             * 2.lambda、内部类或线程类方式实现Runnable接口,实现run()方法
             * 再交给Thread 类
             */
            Thread runThread = new Thread(() -> {
                System.out.println("Runnable");
            });
            // 开启线程
            runThread.start();
    
            /**
             * 3.lambda、内部类或线程类方式实现Callable接口,实现call()方法
             * 再交给Thread 类:FutureTask本质也是Runnable实现类
             */
            FutureTask<String> futureTask = new FutureTask<String>(() -> {
                System.out.println("Callable");
                return "CallableThread";
            });
            Thread callThread = new Thread(futureTask);
            // 开启线程
            callThread.start();
            // 获取call()方法的返回值
            String s = futureTask.get();
            System.out.println("call()方法的返回值:"+s);
        }
    
    }

    Instancier directement le thread créé par la classe Thread sans remplacer la méthode run() ou call() n'a aucune signification pratique ;

    Seuls les threads créés dans la méthode Callable peuvent obtenir la valeur de retour du thread ;

    2.2. État exécutable (RUNNABLE)

    Cet état fait référence à l'état entré après que le thread instancie l'objet et appelle la méthode start(). Le thread est dans un état exécutable et s'il existe des ressources telles qu'un processeur, le programme peut être exécuté.

    Cet état comprend deux étapes au niveau du système d'exploitation : thread prêt et thread en cours d'exécution, mais dans l'état du thread Java, ces deux étapes sont collectivement appelées état Runnable (exécutable).

    Lorsqu'un thread passe de l'état prêt à l'état d'exécution, le point clé est de voir si votre thread a récupéré la ressource CPU (tranche de temps CPU) Celui qui la récupère l'exécutera, et s'il ne la récupère pas, attendez. . Étant donné que la tranche de temps du processeur (temps d'exécution) est très courte, environ dix millisecondes, le temps de changement de thread est très court et le temps nécessaire pour que l'état prêt passe à l'état d'exécution est également très court. Cet état est presque invisible pendant. Développement Modifications, donc en Java, les deux sont considérés comme un tout, en se concentrant sur la capacité du thread à s'exécuter et en le distinguant des autres états, simplifiant davantage le développement des threads. Si votre programme doit s'exécuter pendant une longue période (comme l'écriture d'une boucle infinie) et que l'exécution n'est pas terminée dans une tranche de temps CPU, alors votre thread devra récupérer la tranche de temps CPU suivante seulement après l'avoir saisie. il continue à exécuter le programme. S'il ne l'a pas récupéré, il peut continuer à exécuter le programme. Vous devez ensuite continuer à saisir jusqu'à ce que l'exécution du programme dans le thread soit terminée.

    En fait, vous auriez dû voir ce scénario auparavant. Par exemple, lorsque plusieurs threads exécutent le même programme et impriment les journaux dans le même fichier, les journaux des différents threads seront mélangés, ce qui n'est pas propice au dépannage. Les méthodes courantes pour résoudre ce problème sont les suivantes : premièrement, imprimer les journaux de différents threads dans différents fichiers ; deuxièmement, enregistrer les informations du journal dans un objet chaîne et imprimer les informations du journal dans le fichier en une seule fois à la fin du programme. La deuxième méthode consiste à utiliser une tranche de temps du processeur pour terminer l'impression des informations du journal.

    Remarque : le programme ne peut appeler la méthode start() que sur les threads dans l'état nouvellement créé. N'appelez pas la méthode start() sur les threads dans l'état non nouvellement créé. Cela provoquera une exception IllegalThreadStateException.

    2.3. BLOQUÉ

    Le fil de discussion est en attente du moniteurverrouillage et est bloqué. Un thread a acquis le verrou mais ne l'a pas libéré. ​​D'autres threads sont également venus acquérir le verrou, mais ont constaté qu'ils ne pouvaient pas acquérir le verrou et sont entrés dans l'état bloqué.

    L'état bloqué n'existe que sous accès simultané par plusieurs threads et est différent des deux derniers types de blocage provoqués par le thread lui-même entrant « en attente ».

    Saisie du statut

    • Saisie du bloc/méthode de code synchronisé

    • Verrouillage non obtenu

    Statut de sortie

    • Verrouillage du moniteur obtenu

    2.4. En attente de l'état de réveil (ATTENTE)

    L'ensemble du processus est comme ceci : le thread acquiert d'abord le verrou d'objet dans la méthode de synchronisation d'un objet ; lorsque la méthode d'attente est exécutée, le thread libère le verrou d'objet et le thread est mis en attente. état de cet objet. Queue ; attendez qu'un autre thread acquière le verrou du même objet, puis réveillez le thread dans la file d'attente des objets via la méthode notify() ou notifyAll().

    De l'ensemble du processus, nous pouvons savoir que les méthodes wait(), notify() et notifyAll() doivent obtenir le verrou avant que le thread puisse continuer à s'exécuter, ces trois méthodes doivent donc être placées dans le bloc de code synchronisé /method Exécuter, sinon une exception sera signalée : java.lang.IllegalMonitorStateException.

    在同步代码块中,线程进入WAITING 状态时,锁会被释放,不会导致该线程阻塞。反过来想下,如果锁没释放,那其他线程就没办法获取锁,也就没办法唤醒它。

    进入状态

    • object.wait()

    • thread.join()

    • LockSupport.park()

    退出状态

    • object.notify()

    • object.notifyall()

    • LockSupport.unpark()

    2.5.计时等待状态(TIMED_WAITING)

    一般是计时结束就会自动唤醒线程继续执行后面的程序,对于Object.wait(long) 方法还可以主动通知唤醒。

    注意:Thread类下的sleep() 方法可以放在任意地方执行;而wait(long) 方法和wait() 方法一样,需要放在同步代码块/方法中执行,否则报异常:java.lang.IllegalMonitorStateException。

    进入状态

    • Thread.sleep(long)

    • Object.wait(long)

    • Thread.join(long)

    • LockSupport.parkNanos(long)

    • LockSupport.parkNanos(Object blocker, long nanos)

    • LockSupport.parkUntil(long)

    • LockSupport.parkUntil(Object blocker, long deadline)

    注:blocker 参数为负责此线程驻留的同步对象。

    退出状态

    • 计时结束

    • LockSupport.unpark(Thread)

    • object.notify()

    • object.notifyall()

    2.6.终止(TERMINATED)

    线程执行结束

    • run()/call() 执行完成

    • stop()线程

    • 错误或异常>>意外死亡

    stop() 方法已弃用。

    3.查看线程的6种状态

    通过一个简单的例子来查看线程出现的6种状态。

    案例

    public class Demo3 {
        private static Object object ="obj";
        
        public static void main(String[] args) throws InterruptedException {
    
            Thread thread0 = new Thread(() -> {
                try {
                    // 被阻塞状态(BLOCKED)
                    synchronized (object){
                        System.out.println("thread0 进入:等待唤醒状态(WAITING)");
                        object.wait();
                        System.out.println("thread0 被解除完成:等待唤醒状态(WAITING)");
                    }
                    System.out.println("thread0 "+Thread.currentThread().getState());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            // 新创建状态(NEW)
            System.out.println(thread0.getName()+":"+thread0.getState());
    
            Thread thread1 = new Thread(() -> {
                try {
                    System.out.println("thread1 进入:计时等待状态(TIMED_WAITING)");
                    Thread.sleep(2);
                    System.out.println("thread1 出来:计时等待状态(TIMED_WAITING)");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 被阻塞状态(BLOCKED)
                synchronized (object){
                    System.out.println("thread1 解除:等待唤醒状态(WAITING)");
                    object.notify();
                    System.out.println("thread1 解除完成:等待唤醒状态(WAITING)");
                }
                System.out.println("thread1 "+Thread.currentThread().getState());
            });
            // 新创建状态(NEW)
            System.out.println(thread1.getName()+":"+thread1.getState());
    
            printState(thread0);
            printState(thread1);
    
            // 可运行状态(RUNNABLE)
            thread0.start();
            // 可运行状态(RUNNABLE)
            thread1.start();
    
        }
        
        
        // 使用独立线程来打印线程状态
        private static void printState(Thread thread) {
            new Thread(()->{
                while (true){
                    System.out.println(thread.getName()+":"+thread.getState());
                    if (thread.getState().equals(Thread.State.TERMINATED)){
                        System.out.println(thread.getName()+":"+thread.getState());
                        break;
                    }
                }
            }).start();
        }
    }

    执行结果:简化后的输出结果

    Thread-0:NEW
    Thread-1:NEW
    Thread-0:RUNNABLE
    Thread-1:RUNNABLE
    thread0 进入:等待唤醒状态(WAITING)
    Thread-1:BLOCKED
    thread1 进入:计时等待状态(TIMED_WAITING)
    Thread-0:BLOCKED
    Thread-0:WAITING
    ……
    Thread-0:WAITING
    Thread-1:BLOCKED
    Thread-1:TIMED_WAITING
    ……
    Thread-1:TIMED_WAITING
    Thread-1:BLOCKED
    ……
    Thread-1:BLOCKED
    Thread-0:WAITING
    ……
    Thread-0:WAITING
    thread1 出来:计时等待状态(TIMED_WAITING)
    Thread-0:WAITING
    Thread-1:BLOCKED
    thread1 解除:等待唤醒状态(WAITING)
    Thread-1:BLOCKED
    Thread-0:WAITING
    Thread-0:BLOCKED
    thread1 解除完成:等待唤醒状态(WAITING)
    Thread-1:BLOCKED
    thread1 RUNNABLE
    Thread-0:BLOCKED
    Thread-1:TERMINATED
    thread0 被解除完成:等待唤醒状态(WAITING)
    Thread-0:BLOCKED
    thread0 RUNNABLE
    Thread-0:TERMINATED

    Quels sont les 6 états et cycles de vie des threads Java ?

    最终的执行结果如图。

    注意:因为案例中使用了独立线程来打印不同线程的状态,会出现状态打印稍微延迟的情况。

    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!

    Déclaration:
    Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer