ホームページ  >  記事  >  Java  >  すべてのサブスレッドのタスクが完了した後にメインスレッドをシャットダウンする 4 つの方法

すべてのサブスレッドのタスクが完了した後にメインスレッドをシャットダウンする 4 つの方法

坏嘻嘻
坏嘻嘻オリジナル
2018-09-14 16:27:434082ブラウズ

マルチスレッドは Java において非常に重要な知識です。ここでは Java スレッドのマルチスレッドについてまとめます。ぜひマスターしてください。

    • #メソッド 1 Thread.sleep

    • メソッド 2 ExecutorService

    • メソッド 3 スレッド.join

    • ##メソッド 4 Thread.yield および Thread.activeCount

##コードを書いているときにこのような状況に遭遇しました。各サブスレッドの実行状況を観察する必要があります。処理が実行されないと、

メイン#の後に他のサブスレッドが閉じられてしまいます。 ## メソッドが完了しても、すべてのサブスレッドの詳細な実行ステータスを観察することは不可能であるため、メインスレッドはシャットダウンする前にすべてのサブスレッドの実行が完了するまで待機する必要がありました。

main

関数に Thread を追加します。 sleep(time) ただし、この方法は待ち時間を人為的に設定する必要があるため、完璧ではありませんが、これはベストプラクティスではありません。いくつかの情報とブログを確認し、この目的を達成するための 4 つの方法を紹介します。方法 1 Thread.sleep これはベスト プラクティスではありませんが、最も一般的な方法です。

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");
    }

実行結果:

subthread0finished
subthread1finished
subthread2finished
subthread6finished
subthread4finished
subthread5finished
subthread3finished
subthread9finished
subthread8finished
subthread7finished
main thread finished

メソッド 2 ExecutorService

は、スレッド プールを使用して実装できます。一般的に使用されるスレッド プール オブジェクトは # の実装です。 ##ExecutorService

インターフェイス。

shutdown

およびその他のメソッドを提供します。現在送信されているタスクが子スレッドで実行終了した後、Java プロセスが正常に終了することを確認します。結果は次のとおりです:

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");

    }
このメソッドにはいくつかの小さな欠陥がありますが、出力情報から判断できます。メインスレッドが実際にはサブスレッドよりも前に実行を終了していることがわかります。そのため、このメソッドはサブスレッドの実行を保証することしかできません。 -thread はプログラムが終了する前に実行を終了できますが、サブスレッドの実行が終了した後にメインスレッドが実行されることは保証できません。したがって、コードを変更する必要があります。awaitTermination(time, timeunit)# を追加します。 ## より適切な待ち時間を設定し、サブスレッドの実行が完了するまで待ちます。<pre class="brush:js;toolbar:false;">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</pre>実行結果:

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");

    }

メインスレッドが表示されます。スレッドによって実行された内容は、次の場所に出力されます。この方法は、方法 1 と同様に待機時間を設定する必要がありますが、完璧な方法ではありません。

方法 3 thread.join

thread は、次のことを意味します。このコードを実行しているスレッドは一時停止状態になり、このメソッドを呼び出しているスレッド (ここではこのスレッド) が実行を終了するのを待ってから実行を続行します。次の例では、子スレッドはすべて

main

にあります。はスレッドの上に作成されるため、

main

スレッドで

特定の sub-thread.join

を実行すると、サブスレッドの実行が終了するまで待機してから

main thread のコードは次のとおりです:

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
実行結果:
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");
    }
上記の 2 つの方法と比較して、この方法を使用する利点は、待機時間を設定します。メソッド 4 Thread.yield と Thread.activeCountまず、これら 2 つのメソッドの機能を説明します。 Thread.yield

わかりやすく言うと、これは次のことを意味します。このメソッドを呼び出す現在のスレッドは

放棄し、

CPU

を占有します。ただし、これは現在のスレッドが実行されなくなるわけではありません。 #Thread.activeCount

メソッドは、現在の呼び出しスレッドに対応するスレッド グループ内のアクティブなスレッドの数を返します。 スレッド (新しいスレッド) を作成する場合、

ThreadGroup

パラメータは、現在の呼び出しスレッドに対応するスレッド グループを参照します。このパラメータが指定されていない場合、作成されるスレッドは、このスレッドを作成したスレッドと同じスレッド グループになります。コードは次のとおりです。 :

subthread1finished
subthread2finished
subthread0finished
subthread3finished
subthread6finished
subthread5finished
subthread4finished
subthread9finished
subthread7finished
subthread8finished
main thread finished
実行結果:
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");
    }
非常に重要な点の 1 つは、thisdefaultthreadnum が 2 に設定されているということです。一部のブログではこれを 1 に設定していますが、1 では無限ループが発生し、メインスレッドが終了できなくなるのです。その理由は、除外した後は誰もがそう考えるからです。メイン スレッドが配置されているスレッド グループ内のサブスレッドは、実際には、次のコードを実行した場合には当てはまりません。
subthread0finished
subthread4finished
subthread1finished
subthread8finished
subthread9finished
subthread5finished
subthread2finished
subthread3finished
subthread6finished
subthread7finished
main thread finished
出力:
public static void main(String[] args) {
        Thread.currentThread().getThreadGroup().list();
    }
メイン スレッドが存在するスレッド グループに Monitor Ctrl-Break

という別のスレッドがあることがわかります。したがって、すべての子スレッドを除外した後でも、まだ 2 つのスレッドが存在します。

defaultThreadNum

を 2 に設定する必要があります。

このメソッドでも待ち時間を設定する必要はありません。要約すると、すべてのサブスレッドにメイン スレッドを実装する必要があります。再度実行する前に、方法 3 と方法 4 を使用できます。

関連する推奨事項:

Java スレッド マルチスレッドの包括的な分析

php5非 - スレッドセーフとスレッドセーフの違い

以上がすべてのサブスレッドのタスクが完了した後にメインスレッドをシャットダウンする 4 つの方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。