Maison  >  Article  >  Java  >  Quatre façons d'arrêter le thread principal une fois toutes les tâches des sous-threads terminées

Quatre façons d'arrêter le thread principal une fois toutes les tâches des sous-threads terminées

坏嘻嘻
坏嘻嘻original
2018-09-14 16:27:434082parcourir

Le multi-threading est un point de connaissance très important en Java. Ici, l'éditeur résumera pour vous le multi-threading Java. J'espère que vous pourrez le maîtriser.

    • Méthode un Thread.sleep

    • Méthode deux ExecutorService

    • Méthode trois thread .join

    • Méthode 4 Thread.yield et Thread.activeCount


J'ai rencontré un tel scénario lors de l'écriture du code. Je dois observer l'état d'exécution de chaque sous-thread si aucun traitement n'est effectué, les autres sous-threads seront fermés après la méthode main. est terminé, ce qui rend impossible l'observation de l'état d'exécution détaillé de tous les sous-threads, le thread principal doit donc attendre que tous les sous-threads aient fini de s'exécuter avant de s'arrêter. Dans le passé, l'approche la plus bâclée consistait à ajouter <.> à la fonction main. Cependant, cette méthode n'est pas parfaite car elle nécessite de définir artificiellement le temps d'attente n'est pas la meilleure pratique, j'ai donc vérifié certaines informations et blogs, et voici quatre méthodes pour atteindre cet objectif Thread.sleep(time)Méthode 1 Thread.sleep

Ceci devrait être la méthode la plus courante, bien que ce ne soit pas la meilleure pratique, mais elle peut à peine répondre aux besoins.

Exécution résultats :
public static void main(String[] args) throws InterruptedException{        for(int i=0; i<10; i++){            new Thread("subthread" + i){
                @Override                public void run() {                    try {
                        Thread.sleep(1000);
                        System.out.println(Thread.currentThread().getName() + "finished");
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                }
            }.start();
        }
        Thread.sleep(2000);
        System.out.println("main thread finished");
    }

Méthode 2 ExecutorService
subthread0finished
subthread1finished
subthread2finished
subthread6finished
subthread4finished
subthread5finished
subthread3finished
subthread9finished
subthread8finished
subthread7finished
main thread finished

Elle peut être implémentée à l'aide d'un pool de threads. Les objets de pool de threads couramment utilisés sont des implémentations de l'interface

, qui fournit des méthodes telles que pour garantir que le processus Java se termine normalement une fois l'exécution de la tâche actuellement soumise terminée sur le thread enfant

ExecutorServiceshutdownLe résultat de l'exécution est :

public static void main(String[] args) {        // 创建一个ExecutorService
        ExecutorService ex =  Executors.newCachedThreadPool();        for(int i=0; i<10; i++){            // 添加 task
            ex.submit(new Thread("subthread" + i){

                @Override                public void run() {                    try{
                        Thread.sleep(1000);
                        System.out.println(Thread.currentThread().getName() + "finished");
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                }
            });
        }        // 使用shutdown 会通知executorservice 停止添加其它task 它会等待所有子线程运行结束才退出Java进程
        ex.shutdown();
        System.out.println("main thread finished");

    }

Cette méthode présente quelques défauts mineurs. .Nous pouvons voir à partir des informations de sortie que le thread principal termine réellement son exécution avant le thread enfant, donc cette méthode seule peut garantir que le sous-thread peut terminer son exécution avant la fin du programme, mais elle ne peut pas garantir que le thread principal le sera. exécuté une fois l'exécution du sous-thread terminée. Par conséquent, le code doit être modifié. Ajoutez un

pour définir un temps d'attente plus raisonnable et attendez que l'opération soit terminée.
main thread finished
pool-1-thread-3finished
pool-1-thread-4finished
pool-1-thread-2finished
pool-1-thread-1finished
pool-1-thread-5finished
pool-1-thread-7finished
pool-1-thread-8finished
pool-1-thread-6finished
pool-1-thread-9finished
pool-1-thread-10finished

awaitTermination(time, timeunit)Le résultat de l'opération :

public static void main(String[] args) {        // 创建一个ExecutorService
        ExecutorService ex =  Executors.newCachedThreadPool();        for(int i=0; i<10; i++){            // 添加 task
            ex.submit(new Thread("subthread" + i){

                @Override                public void run() {                    try{
                        Thread.sleep(1000);
                        System.out.println(Thread.currentThread().getName() + "finished");
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                }
            });
        }        // 使用shutdown 会通知executorservice 停止添加其它task 它会等待所有子线程运行结束才退出Java进程
        ex.shutdown();        try {            // 设置等待时间等待子线程运行完毕
            if(!ex.awaitTermination(2000, TimeUnit.MILLISECONDS)){                // 等待时间内子线程并未全部运行完毕就直接关闭
                ex.shutdownNow();
            }
        }catch(InterruptedException e){
            ex.shutdownNow();
        }

        System.out.println("main thread finished");

    }

Vous pouvez voir que le contenu exécuté par le thread principal est affiché à la fin. Cette méthode doit définir le temps d'attente tout comme la méthode 1. Ce n'est pas une méthode parfaite.

pool-1-thread-1finished
pool-1-thread-5finished
pool-1-thread-4finished
pool-1-thread-9finished
pool-1-thread-8finished
pool-1-thread-3finished
pool-1-thread-2finished
pool-1-thread-7finished
pool-1-thread-6finished
pool-1-thread-10finished
main thread finished
Méthode trois thread.join

signifie que le thread exécutant ce code sera dans un état suspendu, en attendant que le thread qui appelle cette méthode (voici ce fil) soit terminé en cours d'exécution avant de continuer à s'exécuter. Dans l'exemple suivant, les sous-threads sont tous créés sur le thread

, donc lors de l'exécution de

dans le thread thread.join, il attendra que le sous-thread ait fini de s'exécuter avant de continuer. en continuant à exécuter main Thread, le code est le suivant : main某一个子线程.joinmain Résultat d'exécution :

public static void main(String[] args) throws InterruptedException{
        List<Thread> list = new ArrayList<>();        for(int i=0; i<10; i++){
            Thread t = new Thread("subthread" + i){
                @Override                public void run() {                    try{
                        Thread.sleep(3000);
                        System.out.println(Thread.currentThread().getName() + "finished");
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                }
            };
            list.add(t);
            t.start();
        }        for(Thread item : list){
            item.join();
        }
        System.out.println("main thread finished");
    }

L'avantage d'utiliser cette méthode par rapport aux deux méthodes ci-dessus est qu'il Il n'est pas nécessaire de définir le temps d'attente.

subthread1finished
subthread2finished
subthread0finished
subthread3finished
subthread6finished
subthread5finished
subthread4finished
subthread9finished
subthread7finished
subthread8finished
main thread finished
méthode 4 Thread.yield et Thread.activeCount

Tout d'abord, expliquons les fonctions de ces deux méthodes

En termes simples, cela signifie céder. Le thread actuel

qui appelle cette méthode occupe les droits de

Mais cela ne signifie pas que le thread actuel ne sera plus exécuté. La méthode Thread.yield renvoie le nombre de threads actifs dans. le groupe de threads correspondant au thread appelant actuel. Lors de la création d'un thread (nouveau Thread), le paramètre 放弃 fait référence à Créer le groupe de threads correspondant au thread. Si ce paramètre n'est pas précisé, le thread créé est le même groupe de threads. comme le fil qui a créé le fil. Le code est le suivant : CPUThread.activeCountThreadGroupRésultat de l'exécution :

public static void main(String[] args) {        // 关键参数
        int defaultThreadNum = 2;        for(int i=0; i<10 ;i++){            new Thread("subthread" + i){
                @Override                public void run() {                    try {
                        Thread.sleep(1000);
                        System.out.println(Thread.currentThread().getName() + "finished");
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                }
            }.start();
        }        while(Thread.activeCount() > defaultThreadNum){            // 当活跃线程数大于设定的默认线程数的时候 主线程让步
            Thread.yield();
        }
        System.out.println("main thread finished");
    }

Un point très clé est que

est défini sur 2. Certains les blogs le mettent à 1, mais 1 provoquera une boucle infinie et le thread principal ne pourra pas se fermer. La raison en est que tout le monde pense que le thread où se trouve le thread principal. Après avoir exclu les sous-threads du groupe, seul le thread principal est. gauche. En fait, ce n'est pas le cas. Par exemple, si nous exécutons le code suivant :
subthread0finished
subthread4finished
subthread1finished
subthread8finished
subthread9finished
subthread5finished
subthread2finished
subthread3finished
subthread6finished
subthread7finished
main thread finished

defaultthreadnumSortie :

public static void main(String[] args) {
        Thread.currentThread().getThreadGroup().list();
    }

Vous pouvez voir où se trouve le fil principal. est également un thread appelé

dans le groupe de threads, donc après avoir exclu tous les sous-threads, il reste encore 2 threads, donc le seuil de jugement de boucle (
java.lang.ThreadGroup[name=main,maxpri=10]    Thread[main,5,main]    Thread[Monitor Ctrl-Break,5,main]
) doit être défini sur 2.

Ceci La méthode n'a pas non plus besoin d'être définie. Temps d'attente.Monitor Ctrl-BreakdefaultThreadNumEn résumé, si vous devez implémenter le thread principal pour qu'il s'exécute une fois que tous les sous-threads ont fini de s'exécuter, vous pouvez utiliser la méthode trois et la méthode quatre.

Recommandations associées :


Analyse complète du multi-threading Java Thread

php5 non -La différence entre thread-safe et thread-safe

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:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn