マルチスレッドは Java において非常に重要な知識です。ここでは Java スレッドのマルチスレッドについてまとめます。ぜひマスターしてください。
メイン#の後に他のサブスレッドが閉じられてしまいます。 ## メソッドが完了しても、すべてのサブスレッドの詳細な実行ステータスを観察することは不可能であるため、メインスレッドはシャットダウンする前にすべてのサブスレッドの実行が完了するまで待機する必要がありました。
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
インターフェイス。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)# を追加します。 ## より適切な待ち時間を設定し、サブスレッドの実行が完了するまで待ちます。<div class="code" style="position:relative; padding:0px; margin:0px;"><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><div class="contentsignin">ログイン後にコピー</div></div>
実行結果: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
main
にあります。はスレッドの上に作成されるため、main
スレッドで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
メソッドは、現在の呼び出しスレッドに対応するスレッド グループ内のアクティブなスレッドの数を返します。 スレッド (新しいスレッド) を作成する場合、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 つは、this
defaultthreadnum が 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 サイトの他の関連記事を参照してください。