このシリーズは、数字をゴールドに精製する過程に基づいており、より良く学ぶために一連のレコードが作成されました。この記事では主に1を紹介します。スレッドとは何ですか。スレッドの基本操作3。デーモンスレッド4。スレッド優先度5。基本スレッド同期操作
1。スレッドとは何ですか
スレッドはプロセス内の実行ユニットです
プロセスにはいくつかのスレッドがあります。
スレッドは、プロセス内の実行ユニットです。
スレッドを使用する理由は、プロセススイッチングが非常にヘビー級操作であり、リソースを消費するためです。複数のプロセスを使用すると、並行性の数はそれほど高くありません。スレッドはスケジューリングユニットが小さく、軽量であるため、スレッドは同時設計でより広く使用されています。
Javaでは、スレッドの概念は、オペレーティングシステムレベルのスレッドの概念に似ています。実際、JVMはJavaのスレッドをオペレーティングシステムのスレッド領域にマッピングします。
2。スレッドの基本操作
2.1スレッドステータス図
上の写真は、Javaのスレッドの基本的な操作を示しています。
スレッドが新しい場合、スレッドは実際には機能しません。エンティティを生成するだけで、このインスタンスの開始方法を呼び出すと、実際にスレッドが開始されます。起動後、実行可能な状態に到達します。 Runnableとは、スレッドのリソースなどが準備され、実行できることを意味しますが、実行状態にあるという意味ではありません。時間スライスの回転により、この時点でスレッドが実行されていない場合があります。私たちにとって、スレッドは実行されたと見なすことができますが、それが実行されているかどうかは、実際には物理CPUのスケジューリングに依存します。スレッドタスクが実行されると、スレッドは終了した状態に到達します。
スレッドの実行中に、一部のロックまたはオブジェクトモニターが適用されることは避けられない場合があります。取得できない場合、スレッドはブロックされ、吊り下げられ、ブロックされた状態に到達します。このスレッドが待機方法を呼び出す場合、それは待機状態にあります。待機状態に入るスレッドは、他のスレッドが通知するのを待ちます。通知が作成された後、待機状態は待機状態から実行可能な状態に切り替えて、実行を継続します。もちろん、待機状態には2つのタイプがあります。1つは、通知されるまで無期限に待つことです。限られた期間を待っていました。たとえば、10秒待っている場合、または通知がない場合、実行可能な状態に自動的に切り替えられます。
2.2新しいスレッドを作成します
スレッドスレッド= newスレッド();
thread.start();
これにより、スレッドが開きます。
注意すべきことの1つはです
スレッドスレッド= newスレッド();
thread.run();
実行方法を直接呼び出すことで、新しいスレッドを開くことはできません。
STARTメソッドは、実際に新しいオペレーティングシステムスレッドの実行メソッドを呼び出します。つまり、startメソッドの代わりに実行方法を直接呼び出すと、新しいスレッドを起動するのではなく、現在のスレッド呼び出しの実行で操作を実行します。
スレッドスレッド= newスレッド( "T1"){@Override public void run(){// dodo auto-enerated method stub.out.println(thread.currentthread()。getName()); }}; thread.start();開始が呼び出された場合、出力はt1threadスレッド= newスレッド( "T1"){@Override public void run(){// todo auto-enerated method stub.out.println(thread.currentthread()。getName()); }}; thread.run();実行されている場合、メインは出力です。 (直接ターンランは実際には通常の機能呼び出しであり、マルチスレッドの役割を達成していません)
実行方法を実装するには、2つの方法があります
最初の方法は、実行方法を直接オーバーライドすることです。現在コードに示されているように、匿名クラスを使用することで最も便利な方法を実現できます。
スレッドスレッド= newスレッド( "T1"){@Override public void run(){// dodo auto-enerated method stub.out.println(thread.currentthread()。getName()); }}; 2番目の方法
スレッドT1 = newスレッド(new createThread3());
createThread3()は、実行可能なインターフェイスを実装します。
Zhang Xiaoxiangのビデオでは、2番目の方法が推奨され、よりオブジェクト指向であると言っています。
2.3スレッドを終了します
thread.stop()は推奨されません。すべてのモニターをリリースします
ソースコードでは、STOPメソッドが非推奨であると明確に述べられており、その理由はJavadocでも説明されています。
その理由は、STOPメソッドが「暴力的」であるためです。スレッドがどこで実行されても、スレッドのドロップをすぐに停止します。
書き込みスレッドがロックを取得したら、データの書き込みを開始します。 ID = 1を記述した後、停止し、名前= 1を設定する準備をするときにロックが解放されます。読み取りスレッドは読み取り操作のためにロックを取得します。 ID読み取りは1で、名前はまだ0であり、データの矛盾を引き起こします。
最も重要なことは、この種のエラーが例外を投げかけず、検出が難しいことです。
2.4スレッド割り込み
スレッドを中断する方法は3つあります
public void thread.interrupt()//割り込みスレッド
public booleanスレッド
public static boolean thread.interrupded()//中断されているかどうかを判断し、現在の割り込みステータスをクリアします
スレッドの中断とは何ですか?
Javaの割り込みメカニズムを理解していない場合、そのような説明は誤解を引き起こす可能性が非常に高いので、スレッドの割り込み方法を呼び出すとスレッドが間違いなく中断されると思います。
実際、Javaの中断はコラボレーションメカニズムです。言い換えれば、スレッドオブジェクトの割り込み方法を呼び出すと、必ずしも実行スレッドが中断されるわけではなく、適切なタイミングでスレッドを遮断する必要があります。各スレッドにはブール割り込み状態があり(必ずしもオブジェクトのプロパティではありません。実際、この状態は実際にはスレッドフィールドではありません)、割り込み方法は単に状態を真に設定します。非ブロッキングスレッドの場合、割り込み状態が変更されます。つまり、スレッド。
public void run(){// thread t1 while(true){thread.yield(); }} t1.interrupt();これは、スレッドT1を中断する効果はありませんが、割り込みステータスビットは変更されます。
このスレッドを非常に優雅に終了したい場合は、これを行う必要があります
public void run(){while(true){if(thread.currentthread()。is interrupted()){system.out.println( "interruted!");壊す; } thread.yield(); }}割り込みを使用すると、データの一貫性が特定の保証を提供します。
キャンセル可能なブロッキング状態のスレッドの場合、これらの機能を待機しているスレッド、swree.sleep()、object.wait()、およびthread.join()など、このスレッドは割り込み信号を受信した後に中断exceptionをスローし、割り込み状態をfalseに戻します。
ブロック状態を解除するスレッドの場合、次のようなコードを書くことができます。
public void run(){while(true){if(thread.currentthread()。is interrupted()){system.out.println( "interruted!");壊す; } try {thread.sleep(2000); } catch(arturnedexception e){system.out.println( "睡眠時に散布される"); //割り込みステータスを設定します。割り込みフラグビットは、例外Thread.currentThread()。 } thread.yield(); }}2.5スレッドハング
スレッドを一時停止して再開します
suspend()はロックを放出しません
resume()の前にロックが発生した場合、両方のデッドロックが発生する方法は非推奨方法であり、推奨されません。
その理由は、Suspendがロックを放出しないため、他のスレッドによって再開されるまでロックされている重要な領域リソースにスレッドがアクセスできないためです。実行されているスレッドのシーケンスを制御できないため、他のスレッドの履歴書方法が最初に実行されると、後で吊り下げられた後は常にロックを占有し、デッドロックが発生します。
次のコードを使用して、このシナリオをシミュレートします
パッケージテスト;パブリッククラステスト{staticオブジェクトu = new object(); static testsuspendthread t1 = new testSusPendThread( "T1"); static testsuspendthread t2 = new testSusPendThread( "T2"); public static class testsuspendthread extends thread {public testsuspendthread(string name){setName(name); } @Override public void run(){synchronized(u){system.out.println( "in" + getName()); thread.currentthread()。suspend(); }} public static void main(string [] args)throws arturnedexception {t1.start(); thread.sleep(100); t2.start(); t1.resume(); t2.resume(); t1.join(); t2.join(); }} T1とT2に同時にロックを競わせ、競合するスレッドは吊り下げられてから再開します。論理的に言えば、スレッドは競争した後に履歴書でリリースする必要があり、その後、別のスレッドがロックと履歴書を競います。
結果出力は次のとおりです。
T1で
T2で
これは、両方のスレッドがロックを競うことを意味しますが、コンソールの赤信号はまだオンになっています。つまり、T1とT2で実行されていないスレッドが必要です。それを捨てて見てみましょう
T2が中断されていることがわかった。これにより、デッドロックが作成されます。
2.6参加してYeild
Yeildはネイティブの静的方法です。この方法は、所有するCPU時間をリリースしてから、他のスレッドと競合することです(YeildのスレッドはまだCPUを競争し、睡眠との違いに注意を払うことに注意してください)。また、Javadocでは、Yeildは基本的に使用されておらず、一般的にデバッグとテストで使用される方法であると説明されています。
結合方法は、他のスレッドが終了するのを待つことを意味します。一時停止セクションのコードと同様に、メインスレッドが終了する前にT1とT2が終了するのを待つ必要があります。終了しない場合、メインスレッドはそこでブロックされます。
パッケージテスト;パブリッククラステスト{public volatile static int i = 0; public static class addthread extends thread {@override public void run(){for(i = 0; i <10000000; i ++); }} public static void main(string [] args)throws arturnedexception {addthread at = new addthread(); at.start(); at.join(); System.out.println(i); }}上記のコードのat.joinが削除された場合、メインスレッドは直接実行され、私の値は非常に小さくなります。結合がある場合、印刷された私は10000000でなければなりません。
では、Joinはどのように実装されていますか?
参加の性質
while(isalive())
{
待機(0);
}
Join()メソッドは時間を過ごすこともできます。つまり、限られた期間を待つことを意味し、この時間の後に自動的に目覚めます。
このような質問があります。スレッドに誰が通知しますか?スレッドクラスで通知を呼び出す場所はありませんか?
Javadocでは、関連する説明が見つかりました。スレッドが完了して終了すると、notifyallメソッドが呼び出され、現在のスレッドインスタンスで待機しているすべてのスレッドを目覚めさせます。この操作はJVM自体によって行われます。
そのため、Javadocは、スレッドインスタンスでWaitを使用して通知/NotifyAllを使用しないように提案してくれました。 JVMはそれ自体を呼び出すため、通話の予想される結果とは異なる場合があります。
3。デーモンスレッド
ガベージコレクションスレッドやJITスレッドなど、バックグラウンドでいくつかの体系的なサービスを静かに完了することは、デーモンスレッドとして理解できます。
すべての非デーモンプロセスがJavaアプリケーション内で終了すると、Java仮想マシンは自然に終了します。
Pythonで実装する方法に関する記事を書きました。ここでチェックしてください。
Javaでデーモンになるのは比較的簡単です。
スレッドT = new DaeMont();
T.SetDaemon(True);
t.start();
これにより、デーモンスレッドが開きます。
パッケージテスト;パブリッククラステスト{public static class daemonthread extends thread {@override public void run(){for(int i = 0; i <10000000; i ++){system.out.println( "hi"); }}} public static void main(string [] args)throws arturtedexception {daemonthread dt = new daemonthread(); dt.start(); }}スレッドDTがデーモンスレッドではない場合、実行後、コンソール出力HIを見ることができます
開始前に参加するとき
dt.setdaemon(true);
コンソールは直接終了し、出力はありません。
4。スレッドの優先順位
スレッドクラスには、スレッドの優先順位を定義する3つの変数があります。
public final static int min_priority = 1; public final static int norm_priority = 5; public final static int max_priority = 10;パッケージテスト;パブリッククラステスト{public static class high extends thread {static int count = 0; @Override public void run(){while(true){synchronized(test.class){count ++; if(count> 10000000){system.out.println( "high");壊す; }}}}} public static class low extends thread {static int count = 0; @Override public void run(){while(true){synchronized(test.class){count ++; if(count> 10000000){system.out.println( "low");壊す; }}}}}} public static void main(string [] args)throws arturtedexception {high high = new high();低low = new low(); high.setpriority(thread.max_priority); low.setpriority(thread.min_priority); low.start(); high.start(); }}高優先度のスレッドと低優先度のスレッドが同時にロックを競い合い、最初に完了したものを確認します。
もちろん、必ずしも優先度で最初に完了する必要はありません。何度も実行した後、優先度の高い完了の可能性は比較的高いことがわかりましたが、優先度が低いまま完了することはまだ可能です。
5。基本的なスレッド同期操作
synchronized and object.wait()obejct.notify()
このセクションの詳細については、以前に書いたブログを参照してください。
注意すべき主なことは
同期してロックするには3つの方法があります。
ロックされたオブジェクトを指定します:指定されたオブジェクトをロックし、同期コードを入力する前に指定されたオブジェクトのロックを取得します。
インスタンスメソッドに直接作用する:現在のインスタンスをロックすることと同等です。同期コードを入力する前に、現在のインスタンスのロックを取得する必要があります。
静的方法に直接作用する:これは、現在のクラスをロックすることと同等です。同期コードを入力する前に、現在のクラスのロックを取得する必要があります。
インスタンスメソッドで動作する場合は、2つの異なるインスタンスを新しいものにしないでください
追加のロックがクラスのクラスであり、2つの異なるインスタンスが新しくなる可能性があるため、クラスが同じである限り、静的な方法で動作します。
待機と通知の使用方法:
どんなロックを使用して、待機を呼び出して通知します
この記事では詳しく説明しません。