0.スレッドの同期に関して(1)マルチスレッドを同期する必要があるのはなぜですか?
スレッドの同期とは、複数のスレッドがうまく協力できるようにして、複数のスレッドが必要に応じてリソースを合理的に占有およびリリースできるようにすることを指します。この目標を達成するために、Javaの同期コードブロックと同期メソッドを使用します。たとえば、マルチスレッドの固定されていない注文実行の問題を解決します。
public class twothreadtest {public static void main(string [] args){thread th1 = new mythread1();スレッドth2 = new mythread2(); th1.start(); th2.start(); }} class mythRead2 extends thread {@override public void run(){for(int i = 0; i <10; i ++)system。 out.println( "スレッド1カウンター:"+i); }} class mythread1 extends thread {@override public void run(){for(int i = 0; i <10; i ++)system。 out.println( "スレッド1カウンター:"+i); }} class mythread1 extends thread {@override public void run(){for(int i = 0; i <10; i ++)system。 out.println( "スレッド2カウンター:"+i); }}この状態でのマルチスレッド実行の結果は、JVMのスレッドスケジューリングに完全に依存する自由に実行をランダムに挿入することです。秩序ある実行が必要な多くの場合、このランダム実行状態は明らかに不適切です。
public class threadtest {public static void main(string [] args){mythread thread = new mythread();スレッドth1 = newスレッド(スレッド);スレッドth2 = newスレッド(スレッド); th1.start(); th2.start(); }} class mythReadはrunnable {@Override public synchronized void run(){for(int i = 0; i <10; i ++)システムを実装します。 out.println(thread。purrentThread()。getName()+"counter:"+i); }}同期方法を使用した後、スレッドを制御して、実行ボディオブジェクトのみを占めることができます。このようにして、実行プロセス中に、スレッドは実行本体のタスクを一度に実行し、ロック状態を終了できます。その後、JVMは別のスレッドを派遣して、一度に実行本体のタスクを実行します。
(2)スレッドの作成と実行のパラダイム:
過去には、スレッドの作成と実行のための独自のプログラミングパラダイムもありました。一般に、実行クラスを定義してrun()メソッドを書き直しましたが、この方法は実行本体と実行されたタスクをまとめます。これは、ソフトウェアエンジニアリングの観点から切り離すことを助長しません。スレッドの実行は、スレッドが実行オブジェクトを介してオブジェクトのタスクを実行することを意味します。この観点から、タスクの処方者を実行クラスから分離すると、マルチスレッドプログラミングのさまざまな役割が明確になり、したがって適切なデカップリングが得られます。以下は、スレッドの作成と実行のためのプログラミングパラダイムです。
public class formalthreadclass {public static void main(string [] args){thread thread = newスレッド(new myrunnable()); thread.start(); }} class myRunnable Implesions runnable {mytask mytask = new mytask(); @Override public void run(){mytask.dotask(); }} class mytask {public void dotask(){system。 out.println( "これは本当のタスクです"); }}
1。同期された原理
Javaでは、各オブジェクトには1つの同期ロックのみがあります。これはまた、同期ロックがオブジェクトに存在することを意味します。
オブジェクトの同期メソッドを呼び出すと、オブジェクトの同期ロックを取得します。たとえば、同期(OBJ)は、「OBJオブジェクト」の同期ロックを取得します。
異なるスレッドによる同期ロックへのアクセスは相互に排他的です。言い換えれば、特定の時点で、オブジェクトの同期ロックは1つのスレッドでのみ取得できます!同期ロックを介して、複数のスレッドで「オブジェクト/メソッド」への相互に排他的なアクセスを実現できます。たとえば、2つのスレッドAとスレッドBがあり、どちらも「オブジェクトOBJの同期ロック」にアクセスします。ある時点で、スレッドAが「OBJの同期ロック」を取得し、いくつかの操作を実行するとします。この時点で、スレッドBは「OBJの同期ロック」を取得しようとします - スレッドBは取得できません。スレッドAが「OBJの同期ロック」をリリースし、実行することのみを待つ必要があります。
2。同期された基本ルール
次の3つに同期した基本的なルールを要約し、例を通してそれらを説明します。
第1条:スレッドが「同期されたメソッド」または「特定のオブジェクト」の「同期コードブロック」にアクセスすると、他のスレッドは「オブジェクト」の「同期メソッド」または「同期コードブロック」へのアクセスからブロックされます。
第2条:スレッドが「特定のオブジェクト」の「同期メソッド」または「同期コードブロック」にアクセスすると、他のスレッドは「このオブジェクト」の非同期コードブロックにアクセスできます。
第3条:スレッドが「特定のオブジェクト」の「同期メソッド」または「同期コードブロック」にアクセスすると、他のスレッドが「オブジェクト」の他の「同期メソッド」または「同期コードブロック」にアクセスすることをブロックします。
(1)第1条:
スレッドが「特定のオブジェクト」の「同期メソッド」または「同期コードブロック」にアクセスすると、他のスレッドは「オブジェクト」の「同期メソッド」または「同期コードブロック」へのアクセスからブロックされます。以下は、「同期コードブロック」に対応するデモプログラムです。
class myRunableはrunnable {@override public void run(){synchronized(this){for(int i = 0; i <5; i ++){shood.sleep(100); // 100ms System.out.println(thread.currentThread()。getName() + "loop" + i); }} catch(arturnedexception ie){}}}} public class demo1_1 {public static void main(string [] args){runnable demo = new myRunable(); //新しい「実行可能なオブジェクト」スレッドT1 =新しいスレッド(デモ、 "T1"); //新しい「スレッドT1」を作成すると、T1は実行可能なオブジェクトスレッドT2 =新しいスレッド(デモ、 "T2")に基づいています。 //新しい「スレッドT2」を作成すると、T2は実行可能なオブジェクトT1.Start()に基づいています。 //「スレッドt1」t2.start();を起動します。 //「スレッドT2」を開始}}実行結果:
T1ループ0T1ループ1T1ループ2T1ループ3T1ループ4T2ループ0T2ループ1T2ループ2T2ループ3T2ループ4
結果は、run()メソッドに「同期された(この)コードブロック」があり、T1とT2が「デモ」実行可能なオブジェクトに基づいて作成されたスレッドであることを示しています。これは、これを同期(これ)で「デモ実行可能なオブジェクト」と見なすことができることを意味します。したがって、スレッドT1とT2は「デモオブジェクトの同期ロック」を共有します。したがって、1つのスレッドが実行されている場合、別のスレッドが「ランニングスレッド」が実行される前に「デモ同期ロック」をリリースするのを待つ必要があります。
確認した場合、この問題を見つけました。次に、上記のコードを変更してから、結果がどのようになっているかを確認し、混乱するかどうかを確認します。変更されたソースコードは次のとおりです。
class mythread extends thread {public mythread(string name){super(name); } @Override public void run(){synchronized(this){try {for(int i = 0; i <5; i ++){thread.sleep(100); // 100ms System.out.println(thread.currentThread()。getName() + "loop" + i); }} catch(arturnedexception ie){}}}} public class demo1_2 {public static void main(string [] args){thread t1 = new Mythread( "T1"); //新しい「スレッドT1」スレッドT2 = new Mythread( "T2"); //新しい「スレッドT2」T1.Start()を作成します。 //「スレッドt1」t2.start();を起動します。 //「スレッドT2」を開始}}コードの説明:Demo1_2とDemo1_1を比較すると、Demo1_2のMythreadクラスはスレッドから直接継承され、T1とT2は両方ともMythRead Childスレッドであることがわかりました。
幸いなことに、「demo1_2のrun()メソッド」は、同期(this)とも呼ばれます。
Demo1_2の実行プロセスはDemo1_1と同じですか?実行結果:
T1ループ0T2ループ0T1ループ1T2ループ1T1ループ2T2ループ2T1ループ3T2ループ3T1ループ4T2ループ4
結果説明:
この結果がまったく驚かないなら、私はあなたが同期とこれをより深く理解していると信じています。それ以外の場合は、ここで分析を読み続けてください。
これは、同期された(これ)、「現在のクラスオブジェクト」、つまり同期(この)が配置されているクラスに対応する現在のオブジェクトを指します。その目的は、「現在のオブジェクトの同期ロック」を取得することです。
Demo1_2の場合、これは同期された(この)でMythreadオブジェクトを表し、T1とT2は2つの異なるMythreadオブジェクトです。したがって、T1とT2が同期(これ)を実行すると、異なるオブジェクトの同期ロックを取得します。 Demo1_1ペアの場合、これは同期(この)でmyRunableオブジェクトを表します。 T1とT2は、myRunableオブジェクトを共有します。したがって、1つのスレッドがオブジェクトの同期ロックを取得し、別のスレッドが待機します。
(2)第2条:
スレッドが「特定のオブジェクト」の「同期メソッド」または「同期コードブロック」にアクセスすると、他のスレッドは「このオブジェクト」の非同期コードブロックにアクセスできます。
以下は、「同期コードブロック」に対応するデモプログラムです。
class count {//同期を含むメソッドは、public void synmethod(){synchronized(this){try {for(int i = 0; i <5; i ++){shood.sleep(100); // 100ms system.out.println(thread.currentthread()。getname() + "Synmethod loop" + i); }} catch(arturnedexception ie){}}} // asynchronous method public void nonsynmethod(){try {for(int i = 0; i <5; i ++){shood.sleep(100); system.out.println(thread.currentthread()。getName() + "nonsynmethod loop" + i); }} catch(arturnedexception ie){}}} public class demo2 {public static void main(string [] args){final count count = new count(); //新しいT1を作成すると、T1は「カウントオブジェクト」スレッドT1 = new runnable(){@Override public void run(){count.synmethod();}}、 "t1"); //新しいT2を作成すると、T2は「countオブジェクト」スレッドのnonsynmethod()メソッドを呼び出します。 t1.start(); // t1 t2.start()を開始します。 // t2を開始}}実行結果:
T1 SYNMETHOD LOOP 0T2 NONSYNMETHOD LOOP 0T1 SYNMETHOD LOOP 1T2 NONSYNMETHOD LOOP 1T1 SYNMETHOD LOOP 2T2 NONSYNMETHOD LOOP 2T1 SYNMETHOD LOOP 3T2 NONSYNMETHOD LOOP 3T1 SYNMETOD LOOP
結果説明:
2つの新しい子スレッドT1とT2がメインスレッドに作成されます。 T1は、同期ブロックを含むカウントオブジェクトのsynmethod()メソッドを呼び出します。 T2は、カウントオブジェクトのnonsynmethod()メソッドを呼び出しますが、これは同期メソッドではありません。 T1が実行されているとき、「カウント同期ロック」を取得するために同期(this)が呼び出されます。 T2は「カウント」同期ロックを使用しないため、T2をブロックしません。
(3)第3条:
スレッドが「特定のオブジェクト」の「同期メソッド」または「同期コードブロック」にアクセスすると、「オブジェクト」の他の「同期メソッド」または「同期コードブロック」への他のスレッドアクセスがブロックされます。
また、上記の例では、同期(これ)を使用して、上記の例でnonsynmethod()メソッド本体を変更します。変更されたソースコードは次のとおりです。
class count {//同期を含むメソッドは、public void synmethod(){synchronized(this){try {for(int i = 0; i <5; i ++){shood.sleep(100); // 100ms system.out.println(thread.currentthread()。getname() + "Synmethod loop" + i); }} catch(arturnedexception ie){}}} //同期を含むメソッドは、public void nonsynmethod(){synchronized(this){for(int i = 0; i <5; i ++){swree.sleep(100); system.out.println(thread.currentthread()。getName() + "nonsynmethod loop" + i); }} catch(arturnedexception ie){}}}} public class demo3 {public static void main(string [] args){final count count = new count(); // t1を作成すると、t1は「countオブジェクト」スレッドのsynmethod()メソッドを呼び出しますt1 = new runnable(){@override public void run(){count.syncmethod();}}、 "t1"); //新しいT2を作成するT2は、「カウントオブジェクト」スレッドT2 = new runnable(){@Override public void run(){count.nonsynmethod();}}、 "t2"); t1.start(); // t1 t2.start()を開始します。 // t2を開始}}実行結果:
T1 SYNMETHOD LOOP 0T1 SYNMETHOD LOOP 1T1 SYNMETHOD LOOP 2T1 SYNMETHOD LOOP 3T1 SYNMETHOD LOOP 4T2 NONSYNMETHOD LOOP 0T2 NONSYNMETHOD LOOP 1T2 NONSYNMETHOD LOOP 2T2 NONSYMETHOD LOOP
結果説明:
2つの新しい子スレッドT1とT2がメインスレッドに作成されます。 T1とT2の両方のコール同期(THIS)は、カウントオブジェクト(カウント)であり、T1とT2の共有カウントです。したがって、T1が実行されている場合、T2がブロックされ、T1が実行され、T2が実行される前に「カウントオブジェクトの同期ロック」がリリースされます。
3。同期されたメソッドと同期コードブロック
「同期された方法」は同期された変更法を使用し、「同期コードブロック」は同期された変更コードブロックを使用します。
同期されたメソッドの例
public synchronized void foo1(){system.out.println( "synchronized method");}同期コードブロックpublic void foo2(){synchronized(this){system.out.println( "synchronized method"); }}これは、同期されたコードブロックで、現在のオブジェクトを指します。これは、OBJに置き換えられるなど、他のオブジェクトに置き換えることもできます。FOO2()は、同期(OBJ)の場合、OBJの同期ロックを取得します。
同期されたコードブロックは、競合制限のあるアクセス領域をより正確に制御し、より効率的に実行することがあります。これが実証する例です。
// demo4.javaのソースコードパブリッククラスdemo4 {public synchronized void synmethod(){for(int i = 0; i <1000000; i ++); } public void synblock(){synchronized(this){for(int i = 0; i <1000000; i ++); }} public static void main(string [] args){demo4 demo = new demo4();長いスタート、diff; start = system.currenttimemillis(); //現在の時間(Millis)demo.syncmethod()を取得します。 //「同期メソッド」を呼び出しますdiff = system.currenttimemillis() - start; //「時差」system.out.println( "syncmethod():"+ diff)を取得します。 start = system.currenttimemillis(); //現在の時間(Millis)demo.syncblock()を取得します。 //「同期メソッドブロック」を呼び出すdiff = system.currenttimemillis() - start; //「時差」system.out.println( "syncblock():"+ diff)を取得します。 }} (一度)実行結果:
synmethod():11synblock():3
4.インスタンスロックとグローバルロック
インスタンスロック - インスタンスオブジェクトにロックされています。クラスがシングルトンの場合、ロックにはグローバルロックの概念もあります。
(1)同期されたキーワードは、インスタンスロックに対応します。
(2)グローバルロック - ロックはクラスをターゲットにしています。インスタンスがいくつのオブジェクトであっても、スレッドはロックを共有します。
グローバルロックは、静的同期に対応しています(またはこのクラスのクラスまたはクラスローダーオブジェクトにロックされています)。
「インスタンスロック」と「グローバルロック」の非常に鮮明な例があります。
pulbic class Something {public synchronized void issynca(){} public synchronized void issyncb(){} public static synchronized void csynca(){} public static synchronized void csyncb(){}}}}と仮定すると、何かに2つのインスタンスxとyがあります。次の4セットの式で取得されたロックを分析します。
(1)x.issynca()およびx.issyncb()
(2)x.issynca()およびy.issynca()
(3)x.csynca()およびy.csyncb()
(4)x.issynca()およびsoments.csynca()
(1)同時にアクセスできません。
Issynca()とIssyncb()は両方とも同じオブジェクトにアクセスする同期ロックであるためです(オブジェクトX)!
// locktest1.javaのソースコードクラス何か{public synchronized void issynca(){try {for(int i = 0; i <5; i ++){thread.sleep(100); // Sleep 100ms System.out.println(thread.currentThread()。getName()+":ysisynca"); }} catch(arturnedexception ie){}} public synchronized void issyncb(){try {for(int i = 0; i <5; i ++){thread.sleep(100); // 100ms system.out.println(thread.currentthread()。getname()+":sisyncb"); }} catch(arturnedexception ie){}}} public class locktest1 {something x = new soments();何かy = new何か(); //(01)x.issynca()とx.issyncb()private void test1(){// create new t11、t11はx.issynca()スレッドt11 = new runnable(){@override public void run(){x.isnca();}}、 "t11"); //新しいT12を作成すると、T12はx.issyncb()スレッドt12 = new runnable(){@override public void run(){x.issyncb();}}、 "t12"); t11.start(); // t11 t12.start()を開始します。 // t12を開始} public static void main(string [] args){locktest1 demo = new locktest1(); demo.test1(); }}実行結果:
T11:ISSYNCAT11:ISSYNCAT11:ISSYNCAT11:ISSYNCAT12:ISSYNCBT12:ISSYNCBT12:ISSYNCBT12:ISSYNCBT12:ISSYNCBT12:ISSYNCBT12:ISSYNCBT12:ISSYNCBT12:ISSYNCBB
(2)同時にアクセスできます
同じオブジェクトの同期ロックにアクセスしていないため、x.issynca()はxの同期ロックにアクセスし、y.issynca()はyの同期ロックにアクセスします。
// locktest2.javaのソースコードクラス何か{public synchronized void issynca(){try {for(int i = 0; i <5; i ++){thread.sleep(100); // Sleep 100ms System.out.println(thread.currentThread()。getName()+":ysisynca"); }} catch(arturnedexception ie){}} public synchronized void issyncb(){try {for(int i = 0; i <5; i ++){thread.sleep(100); // 100ms System.out.println(thread.currentthread()。getName()+":ysisyncb"); }} catch(arturnedexception ie){}} public static synchronized void csynca(){try {for(int i = 0; i <5; i ++){thread.sleep(100); // Sleep 100ms System.out.println(thread.currentThread()。getName()+":csynca"); }} catch(arturnedexception ie){}} public static synchronized void csyncb(){for(int i = 0; i <5; i ++){shood.sleep(100); // 100ms System.out.println(thread.currentthread()。getName()+":csyncb"); }} catch(arturnedexception ie){}}} public class locktest2 {soments x = new soments();何かy = new何か(); //(02)x.issynca()とy.issynca()private void test2(){// create new t21、t21はx.issynca()スレッドt21 = new runnable(){@override public void run(){x.issynca();};}、 "21"; //新しいT22を作成し、T22はx.issyncb()スレッドT22 = new runnable(){@override public void run(){y.issynca();}}、 "t22"); t21.start(); // t21 t22.start()を開始します。 // t22を開始} public static void main(string [] args){locktest2 demo = new locktest2(); demo.test2(); }}実行結果:
T21:ISSYNCAT22:ISSYNCAT21:ISSYNCAT22:ISSYNCAT21:ISSYNCAT21:ISSYNCAT21:ISSYNCAT21:ISSYNCAT21:ISSYNCAT21:ISSYNCAT21:ISSYNCAT22:ISSYNCAT21:ISSYNCAT2:ISSYNCAT2:ISSYNCAA
(3)同時にアクセスできません
csynca()とcsyncb()はどちらも静的タイプであるため、x.csynca()はsoments.issynca()と同等であり、y.csyncb()はsoments.issyncb()と同等であり、同期ロックを共有し、同時に質問することはできません。
// locktest3.javaのソースコードクラス何か{public synchronized void issynca(){try {for(int i = 0; i <5; i ++){thread.sleep(100); // Sleep 100ms System.out.println(thread.currentThread()。getName()+":ysisynca"); }} catch(arturnedexception ie){}} public synchronized void issyncb(){try {for(int i = 0; i <5; i ++){thread.sleep(100); // 100ms System.out.println(thread.currentthread()。getName()+":ysisyncb"); }} catch(arturnedexception ie){}} public static synchronized void csynca(){try {for(int i = 0; i <5; i ++){thread.sleep(100); // Sleep 100ms System.out.println(thread.currentThread()。getName()+":csynca"); }} catch(arturnedexception ie){}} public static synchronized void csyncb(){for(int i = 0; i <5; i ++){shood.sleep(100); // 100ms System.out.println(thread.currentthread()。getName()+":csyncb"); }} catch(arturnedexception ie){}}} public class locktest3 {something x = new soments();何かy = new何か(); //(03)x.csynca()とy.csyncb()private void test3(){// create new t31、t31はx.issynca()スレッドt31 = new runnable(){@override public void run(){x.csynca(); //新しいT32を作成すると、T32はx.issyncb()スレッドt32 = new swrep(new runnable(){@override public void run(){y.csyncb();}}、 "t32")を呼び出します。 t31.start(); // t31 t32.start()を開始します。 // t32を開始} public static void main(string [] args){locktest3 demo = new locktest3(); demo.test3(); }}実行結果:
T31:CSYNCAT31:CSYNCAT31:CSYNCAT31:CSYNCAT31:CSYNCAT32:CSYNCBT32:CSYNCBT32:CSYNCBT32:CSYNCBT32:CSYNCBT32:CSYNCBT32:CSYNCBT32:CSYNCBT32:CSYNCBT32:CSYNCBT32:CSYNCBT32:CSYNCBT32 csyncb
(4)同時にアクセスできます
Issynca()はインスタンスメソッドであるため、x.issynca()はオブジェクトxのロックを使用します。 csynca()は静的な方法ですが、何か。csynca()は、それが使用されている「クラスロック」であることを理解できます。したがって、それらに同時にアクセスできます。
// locktest4.javaのソースコードクラス何か{public synchronized void issynca(){try {for(int i = 0; i <5; i ++){thread.sleep(100); // Sleep 100ms System.out.println(thread.currentThread()。getName()+":ysisynca"); }} catch(arturnedexception ie){}} public synchronized void issyncb(){try {for(int i = 0; i <5; i ++){thread.sleep(100); // 100ms System.out.println(thread.currentthread()。getName()+":ysisyncb"); }} catch(arturnedexception ie){}} public static synchronized void csynca(){try {for(int i = 0; i <5; i ++){thread.sleep(100); // Sleep 100ms System.out.println(thread.currentThread()。getName()+":csynca"); }} catch(arturnedexception ie){}} public static synchronized void csyncb(){for(int i = 0; i <5; i ++){shood.sleep(100); // 100ms system.out.println(thread.currentthread()。getname()+":csyncb"); }} catch(arturnedexception ie){}}} public class locktest4 {something x = new soments();何かy = new何か(); //(04)x.issynca()とsomeint.csynca()private void test4(){// create new t41、t41はx.issynca()スレッドt41 = new runnable(){@override public void run(){x.issynca();};}; //新しいT42を作成すると、T42はx.issyncb()スレッドT42 = new runnable(){@override public void run(){someint.csynca();}}、 "t42"); t41.start(); // t41 t42.start()を開始します。 // t42を開始} public static void main(string [] args){locktest4 demo = new locktest4(); demo.test4(); }}実行結果:
T41:ISSYNCAT42:CSYNCAT41:ISSYNCAT42:CSYNCAT41:ISSYNCAT42:CSYNCAT41:CSYNCAT42:CSYNCAT41:CSYNCAT41:CSYNCAT41:ISSYNCAT42:CSYNCAT41:CSYNCAT42:CSYNCAA