Javaマルチスレッド(1つ)
Javaの非常に重要な知識ポイントとして、ここでそれを要約する必要があります。
1。スレッドと5つの基本的な状態のライフサイクル
Javaのスレッドのライフサイクルについては、まず次の古典的な写真を見てみましょう。
上記の図は、基本的に、Javaのマルチスレッドの重要な知識ポイントをカバーしています。上記の図の知識ポイントをマスターすると、基本的にJavaでマルチスレッドをマスターします。主に:
Javaスレッドには5つの基本状態があります
新しい状態(新しい):スレッドオブジェクトペアが作成されると、次のような新しい状態に入ります。
Ready State(実行可能):スレッドオブジェクトのstart()メソッド(t.start();)の場合、スレッドは準備ができた状態に入ります。準備が整った状態のスレッドは、スレッドの準備ができており、CPUがいつでも実行をスケジュールするのを待っていることを意味します。T.Start()が実行された直後にスレッドが実行されることではありません。
ランニング状態: CPUが準備ができた状態でスレッドのスケジュールを開始すると、スレッドを本当に実行できます。つまり、実行中の状態に入ります。注:Ready Stateは、実行状態への唯一のエントリです。つまり、スレッドが実行されて実行された状態に入りたい場合、最初に準備ができている必要があります。
ブロック状態:何らかの理由で、実行状態のスレッドがCPUの使用を一時的に放棄し、実行を停止します。この時点で、ブロッキング状態に入ります。実行中の状態に入るために、CPUから再び呼び出される機会はありません。ブロッキングの理由によると、ブロッキング状態は3つのタイプに分けることができます。
1。ブロッキングを待つ:実行中の状態のスレッドは、wait()メソッドを実行して、スレッドがブロッキング状態を待機することを入力します。
2。同期ブロッキング - スレッドは、同期化された同期ロックを取得できません(ロックは他のスレッドで占有されているため)、同期されたブロッキング状態に入ります。
3。その他のブロッキング - スレッドは、スレッドのSleep()またはJoin()を呼び出すか、I/O要求を発行することにより、ブロッキング状態を入力します。 Sleep()状態がタイムアウトしたとき、Join()がスレッドが終了またはタイミングアウトするのを待っているか、I/O処理が完了した場合、スレッドは準備ができた状態に再入力されました。
DEAD:スレッドは、例外のために実行されるか、run()メソッドを終了するか、スレッドがライフサイクルを終了しました。
2。Java Multithreadsの作成とスタートアップ
Javaにはスレッド作成には3つの基本的な形式があります
1.スレッドクラスを継承し、クラスのrun()メソッドをオーバーライドします。
class mythreadはスレッドを拡張します{private int i = 0; @Override public void run(){for(i = 0; i <100; i ++){system.out.println(thread.currentthread()。getname() + "" + i); }}} public class threadtest {public static void main(string [] args){for(int i = 0; i <100; i ++){system.out.println(thread.currentthread()。getName() + "" + i); if(i == 30){thread mythread1 = new mythread(); //新しいスレッドを作成するmythread1 //新しいスレッドを作成するmythread2このスレッドは、新しい状態mythread1.start()に入ります。 // start()メソッドを呼び出して、スレッドに準備ができた状態mythread2.start()を入力するようにします。 // start()メソッドを呼び出して、スレッドに対応状態を入力する}}}}上に示すように、スレッドクラスを継承するように、新しいスレッドクラスのMythReadは、run()メソッドを上書きすることによって定義されます。ここでは、run()メソッドのメソッドボディは、スレッドが完了する必要があるタスクを表し、スレッド実行ボディと呼ばれます。このスレッドクラスオブジェクトを作成すると、新しいスレッドが作成され、新しいスレッド状態に入ります。スレッドオブジェクトによって参照されるstart()メソッドを呼び出すことにより、スレッドは準備ができた状態に入ります。現時点では、CPUスケジューリングのタイミングに応じて、スレッドをすぐに実行できない場合があります。
2。実行可能なインターフェイスを実装し、インターフェイスのrun()メソッドをオーバーライドします。 run()メソッドは、スレッド実行本体でもあり、実行可能な実装クラスのインスタンスを作成し、このインスタンスをスレッドクラスのターゲットとして使用してスレッドオブジェクトを作成します。スレッドオブジェクトは実際のスレッドオブジェクトです。
クラスmyrunnableは実行可能{private int i = 0; @Override public void run(){for(i = 0; i <100; i ++){system.out.println(thread.currentthread()。getname() + "" + i); }}} public class threadtest {public static void main(string [] args){for(int i = 0; i <100; i ++){system.out.println(thread.currentthread()。getName() + "" + i); if(i == 30){runnable myRunnable = new myRunnable(); //実行可能な実装クラススレッドスレッド1 = newスレッド(myrunnable)のオブジェクトを作成します。 //スレッドターゲットスレッドとしてmyRunnableを使用して新しいスレッドを作成するスレッド2 = newスレッド(myrunnable); thread1.start(); // start()メソッドを呼び出して、スレッドにready statre2.start()を入力するようにします。 }}}}誰もが新しいスレッドを作成する上記の2つの方法に精通していると思います。では、スレッドと実行可能な関係は何ですか?まず次の例を見てみましょう。
public class threadtest {public static void main(string [] args){for(int i = 0; i <100; i ++){system.out.println(thread.currentthread()。getName() + "" + i); if(i == 30){runnable myRunnable = new myRunnable();スレッドスレッド= new mythread(myrunnable); thread.start(); }}}} class myrunnable runnable {private int i = 0; @Override public void run(){system.out.println( "in myrunnable run"); for(i = 0; i <100; i ++){system.out.println(thread.currentthread()。getname() + "" + i); }}} class mythread extends thread {private int i = 0; public mythread(runnable runnable){super(runnable); } @Override public void run(){system.out.println( "in mythread run"); for(i = 0; i <100; i ++){system.out.println(thread.currentthread()。getname() + "" + i); }}}同様に、実行可能なインターフェイスを実装するスレッドの作成にも同じことが言えます。違いは、
1スレッドスレッド= new mythread(myrunnable);
では、この方法は新しいスレッドを正常に作成できますか?答えはイエスです。この時点でのスレッド実行本体に関しては、myrunnableインターフェイスのrun()メソッドまたはmythreadクラスのrun()メソッドですか?出力を通じて、スレッド実行本体はMythReadクラスのrun()メソッドであることがわかります。実際、スレッドクラス自体が実行可能なインターフェイスを実装し、run()メソッドが実行可能なインターフェイスで最初に定義されるため、理由は非常に単純です。
public interface runnable {public abstract void run(); }スレッドクラスの実行可能なインターフェイスでのrun()メソッドの実装を見てみましょう。
@Override public void run(){if(target!= null){target.run(); }}つまり、スレッドクラスでrun()メソッドを実行すると、最初にターゲットが存在するかどうかが判断されます。それが存在する場合、ターゲットのrun()メソッドが実行されます。つまり、実行可能なインターフェイスを実装し、run()メソッドを上書きするクラスのrun()メソッドです。ただし、上記の列では、多型が存在するため、スレッドクラスのrun()メソッドはまったく実行されませんが、ランタイムタイプ、つまりMythreadクラスのrun()メソッドは直接実行されます。
3.呼び出し可能なインターフェイスを使用してスレッドを作成します。具体的には、呼び出し可能なインターフェイスの実装クラスを作成し、Clall()メソッドを実装します。 FutureTaskクラスを使用して、呼び出し可能な実装クラスオブジェクトをラップし、このFutureTaskオブジェクトをスレッドオブジェクトのターゲットとして使用してスレッドを作成します。
少し複雑に思えますが、例を直接見るかどうかは明らかです。
public class threadtest {public static void main(string [] args){callable <integer> mycallable = new mycallable(); // myCallableオブジェクトFutureTask <Integer> ft = new FutureTask <Integer>(myCallable); // futureTaskを使用して、myCallableオブジェクトを(int i = 0; i <100; i ++){system.out.println(thread.currentthread()。getName() + "" + i); if(i == 30){thread thread = new Thread(ft); // futureTaskオブジェクトスレッドオブジェクトスレッドのターゲットとして新しいスレッドを作成します。Start(); //スレッドは準備ができた状態に入ります}} system.out.println( "ループのメインスレッドが実行されました.."); try {int sum = ft.get(); //新しく作成された新しいスレッドsystem.out.println( "sum =" + sum)のcall()メソッドによって返された結果を取得します。 } catch(arturnedexception e){e.printstacktrace(); } catch(executionException e){e.printstacktrace(); }}} class myCallable Implements Callable <integer> {private int i = 0; // run()メソッドとは異なり、call()メソッドには@override public integer call(){int sum = 0; for(; i <100; i ++){system.out.println(thread.currentthread()。getName() + "" + i); sum += i; } return sum; }}まず、呼び出し可能なインターフェイスを実装する際に、run()メソッドはrun()メソッドではなく、call()メソッドであることがわかりました。この呼び出し()メソッドはスレッド実行本体であり、返品値もあります!新しいスレッドを作成するとき、MyCallableオブジェクトはFutureTaskにラップされ、スレッドオブジェクトのターゲットとしても機能します。次に、FutureTaskクラスの定義を見てください。
Public Class FutureTask <v>実装runnableFuture <v> {// ....} public interface runnablefuture <v>は、runnable、future <v> {void run(); }したがって、FutureTaskクラスは実際に実行可能なインターフェースと将来の両方のインターフェイスを実装しているため、将来と実行可能な二重特性を備えていることがわかりました。実行可能な機能を介して、スレッドオブジェクトのターゲットとして使用でき、将来の機能により、新しく作成されたスレッドでcall()メソッドの返信値を取得できます。
このプログラムを実行した後、Sum = 4950が常に最後の出力であることがわかります。 「ループのメインスレッドが実行されました...」は、子スレッドループの中央で出力される可能性があります。 CPUのスレッドスケジューリングメカニズムから、「ループのメインスレッドが実行された...」の出力タイミングに問題がないことを知っています。
その理由は、子スレッドのcall()メソッドがft.get()メソッドを介して取得されると、子スレッドのメソッドがまだ実行されていない場合、ft.get()メソッドは、返品値が取得される前にcall()メソッドが実行されるまでブロックされるためです。
上記は、主に3つの一般的なスレッド作成方法を説明しています。スレッドの起動については、それらはすべてスレッドオブジェクトのstart()メソッドと呼ばれます。 Start()メソッドを同じスレッドオブジェクトで2回呼び出すことはできないことに注意することが重要です。
iii。 Java Multithreadingの準備、実行、および死亡のステータス
準備ができた状態は実行状態に変換されます。このスレッドがプロセッサリソースを取得するとき。
実行状態は準備が整った状態に変換されます。このスレッドが積極的にevel()メソッドを呼び出すとき、または実行中にプロセッサリソースを失います。
実行状態は死んだ状態に変換されます:スレッド実行本体が完了するか、例外が発生したとき。
ここでは、スレッドのevel()メソッドが呼び出されると、スレッドが実行状態から準備ができている状態に遷移するが、CPUの既製状態のスレッドには特定のランダム性があることに注意する必要があります。したがって、aスレッドがhired()メソッドを呼び出した後、CPUはまだAスレッドをスケジュールしていることがあります。
実際のビジネスニーズにより、スレッドを特定の機会に終了する必要があることがよくあります。現在最も一般的な方法は、ブール変数を設定することであり、条件が満たされると、スレッド実行本体が迅速に実行されます。のように:
public class threadtest {public static void main(string [] args){myrunnable myrunnable = new myRunnable();スレッドスレッド= newスレッド(myrunnable); for(int i = 0; i <100; i ++){system.out.println(thread.currentthread()。getname() + "" + i); if(i == 30){thread.start(); } if(i == 40){myrunnable.stopthread(); }}}} class myrunnable runnable {private boolean stop; @Override public void run(){for(int i = 0; i <100 &&!stop; i ++){system.out.println(thread.currentthread()。getName() + "" + i); }} public void stopthread(){this.stop = true; }}将来、関連記事を整理し続けます。このサイトへのご支援ありがとうございます!
一連の記事:
Javaマルチスレッドインスタンスの説明(i)
Javaマルチスレッドインスタンスの詳細な説明(ii)
Javaマルチスレッドインスタンスの詳細な説明(iii)