この記事では、Javaの同期(オブジェクトロック)と静的同期(クラスロック)の違いについて説明します。次のように、参照のために共有してください。
同期と静的同期の違い
これら2つの使用法の分析を分析することにより、Javaのロックの概念を理解できます。 1つはインスタンスロックです(インスタンスオブジェクトにロックされています。クラスがシングルトンの場合、ロックにはグローバルロックの概念もあります)、もう1つはグローバルロックです(ロックはクラスでターゲットにされています。インスタンスがどれだけ多くのオブジェクトであっても、スレッドはロックを共有します)。インスタンスロックは同期されたキーワードに対応し、クラスロック(グローバルロック)は静的同期(またはクラスのクラスまたはクラスローダーオブジェクトにロックされている)に対応します。
次の記事には、良い要約があります。
1.同期化された同期と静的同期の違い
同期されたロッククラスの現在のインスタンス(現在のオブジェクト)は、他のスレッドが同時にクラスのインスタンスのすべての同期ブロックにアクセスしないようにします。これは「クラスの現在のインスタンス」であることに注意してください。クラスの2つの異なるインスタンスにそのような制約はありません。
その後、静的同期は、クラスのすべてのインスタンスの同時アクセスを制御するために発生し、静的同期はマルチスレッドのクラスのすべてのインスタンスを制限して、JVMのクラスに対応するコードブロックに同時にアクセスします。実際、クラスのインスタンスを生成した後、クラスのメソッドまたはコードブロックに同期されている場合、インスタンスには、インスタンスの同期された保護ブロックにスレッドが同時にアクセスするのを防ぐための監視ブロックもあります。静的同期は、クラスのすべてのインスタンスに共通の監視ブロックです。これは、2つの違いです。言い換えれば、同期はこれと同等です。一方、静的同期は何かと同等です。 (後で対処)
日本の著者であるジー・チェンガオの「Java Multithreaded Design Pattern」には、次のようなコラムがあります。
pulbic class someint(){public synchronized void issynca(){} public synchronized void issyncb(){} public static synchronized void csynca(){} public static synchronized void csyncb(){}}}}したがって、何かクラスの2つのインスタンスxとyがある場合、次のメソッドグループに複数のスレッドで同時にアクセスされる場合はどうなりますか?
axissynca()およびx.issyncb()
bxissynca()およびy.issynca()
cxcsynca()およびy.csyncb()
dxissynca()and something.csynca()
ここで、それが判断できることは明らかです:
a、すべて同じインスタンス(x)への同期ドメインアクセスであるため、同時にアクセスすることはできません。 (マルチスレッドでXにアクセスする異なる同期ドメインに同時にアクセスできません)
x.issynca()が複数のスレッドでアクセスされる場合、同じインスタンスであり、同じ方法でロックされているため、複数のスレッドで同時にアクセスできません。 (マルチスレッドでXにアクセスするのと同じ同期ドメインに同時にアクセスできません)
bはさまざまなインスタンス用であるため、同時にアクセスできます(オブジェクトロックには、異なるオブジェクトインスタンスのロック制約がありません)
Cは静的に同期しているため、異なるインスタンスはまだ制限されています。これはsomething.issynca()およびsomeint.issyncb()に相当するため、同時にアクセスすることはできません。
したがって、D?はどうですか、本の答えに同時にアクセスできます。答えの理由は、同期されたものであるため、インスタンスメソッドと同期クラスメソッドはロックとは異なるためです。
個人分析とは、同期された静的同期が2つのギャングと同等であり、それぞれが独自のコントロールを持ち、互いに制約がなく、同時にアクセスできることを意味します。
例えば:
public class testsynchronized {public synchronized void test1(){int i = 5; while(i--> 0){system.out.println(thread.currentthread()。getname() + ":" + i); {thread.sleep(500)を試してください。 } catch(arturtedexception ie){}}} public static同期Void test2(){int i = 5; while(i--> 0){system.out.println(thread.currentthread()。getname() + ":" + i); {thread.sleep(500)を試してください。 } catch(arturtedexception ie){}}} public static void main(string [] args){final testsynchronized myt2 = new testsynchronized(); Thread test1 = new Thread(new runnable(){public void run(){myt2.test1();}}、 "test1");スレッドtest2 = newスレッド(new runnable(){public void run(){testsynchronized.test2();}}、 "test2"); test1.start(); test2.start(); // testrunnable tr = new testRunnable(); //スレッドtest3 = newスレッド(TR); // test3.start(); }}Test1:4 Test2:4 Test1:3 Test2:3 Test2:2 test1:2 test2:1 test1:1 test1:0 test2:0
上記のコード同期は、静的メソッドとインスタンスメソッドを同時に変更しますが、実行結果は交互に実行されます。これにより、クラスロックとオブジェクトロックが2つの異なるロックであり、異なる領域を制御し、互いに干渉しません。同様に、スレッドはオブジェクトロックを取得しますが、このタイプのロックを取得することもできます。つまり、同時に2つのロックを取得し、許可されます。
結論は:
A:同期静的は、特定のクラスの範囲です。同期された静的CSYNC {}は、複数のスレッドの複数のインスタンスがこのクラスの同期静的メソッドに同時にアクセスすることを防ぎます。クラスのすべてのオブジェクトインスタンスで動作します。
B:同期は、インスタンスの範囲です。同期Issync(){}は、このインスタンスがこのクラスの同期されたメソッドに同時にアクセスすることを防ぎます。
実際、要約するのは非常に簡単です。
2。同期された方法と同期コードを速くすることの違い
同期されたメソッド(){}と同期(this){}には違いはありませんが、同期されたメソッド(){}は読解力に便利ですが、同期(this){}は競合制限領域をより正確に制御でき、より効率的に実行できます。
2つの方法間の効率の比較:
1.ブロックを同期すると、コードは次のとおりです。
java.util.concurrent.countdownlatchをインポートします。 java.util.concurrent.executorserviceをインポートします。 java.util.concurrent.executorsをインポートします。 public class testsynchronized { / ** * @param args * / public static void main(string [] args){executorservice service = executors.newcachedthreadpool(); final countdownlatch cdorder = new CountDownLatch(1); final countdownlatch cdanswer = new CountDownLatch(3); final synchonizedclass sc = new SynchonizedClass(); for(int i = 0; i <3; i ++){runnable runnable = new runnable(){public void run(){try {cdorder.await(); sc.start(); cdanswer.countdown(); } catch(Exception e){e.printstacktrace(); }}}; service.execute(runnable); } try {thread.sleep((long)(math.random()*10000)); system.out.println( "thread" + thread.currentthread()。getName() + "公開実行コマンド"); cdorder.countdown(); long begintime = system.currenttimemillis(); system.out.println( "thread" + thread.currentthread()。getName() + "コマンドが送信され、結果を待っています"); cdanswer.await(); system.out.println( "swreet" + thread.currentthread()。getName()) + "すべての応答結果が受信されました。 } catch(Exception e){e.printstacktrace(); } service.shutdown(); }} class synchonizedclass {public void start()throws arturnedexception {thread.sleep(100); //他のロジックを実行して時間同期(this){system.out.println( "10ミリ秒で実行しました"); }}}操作結果は次のとおりです。
スレッドメインが実行コマンドをリリースし、スレッドメインがコマンドを送信し、実行して10ミリ秒を使用した結果を待っています
10ミリ秒で実行しています
10ミリ秒で実行しています
スレッドメインはすべての応答結果を受け取り、時間は次のとおりです。
同期方法、コードは次のとおりです。
java.util.concurrent.countdownlatchをインポートします。 java.util.concurrent.executorserviceをインポートします。 java.util.concurrent.executorsをインポートします。 public class testsynchronized { / ** * @param args * / public static void main(string [] args){executorservice service = executors.newcachedthreadpool(); final countdownlatch cdorder = new CountDownLatch(1); final countdownlatch cdanswer = new CountDownLatch(3); final synchonizedclass sc = new SynchonizedClass(); for(int i = 0; i <3; i ++){runnable runnable = new runnable(){public void run(){try {cdorder.await(); sc.start(); cdanswer.countdown(); } catch(Exception e){e.printstacktrace(); }}}; service.execute(runnable); } try {thread.sleep((long)(math.random()*10000)); system.out.println( "thread" + thread.currentthread()。getName() + "公開実行コマンド"); cdorder.countdown(); long begintime = system.currenttimemillis(); system.out.println( "thread" + thread.currentthread()。getName() + "コマンドが送信され、結果を待っています"); cdanswer.await(); system.out.println( "swreet" + thread.currentthread()。getName()) + "すべての応答結果が受信されました。 } catch(Exception e){e.printstacktrace(); } service.shutdown(); }} class synchonizedclass {public synchronized void start()throws arturnedexception {swree.sleep(100); //他のロジック時間// synchronized(this){system.out.println( "10 ms"); //}}}操作結果は次のとおりです。
スレッドメインが実行コマンドをリリースし、スレッドメインがコマンドを送信し、実行して10ミリ秒を使用した結果を待っています
10ミリ秒で実行しています
10ミリ秒で実行しています
スレッドメインはすべての応答結果を受け取り、時間は次のとおりです。
2つの違いは次のとおりです。222ms。
比較は、同期コードブロックが同期方法よりも効率的であることを示しています。
補足記憶:
1.同期されたキーワードには2つのスコープがあります。
1)オブジェクトインスタンス内にあります。同期AMETHOD(){}は、複数のスレッドがこのオブジェクトの同期メソッドに同時にアクセスするのを防ぐことができます(オブジェクトに1つのスレッドが同期されたメソッドのいずれかにアクセスする限り、他のスレッドが同時にオブジェクトの同期メソッドにアクセスできない限り)。現時点では、異なるオブジェクトインスタンスの同期された方法は途切れることができません。つまり、他のスレッドは、同じクラスの別のオブジェクトインスタンスの同期メソッドに同時にアクセスできます。
2)特定のクラスの範囲です。同期された静的ASTATICMETHOD {}は、複数のスレッドで異なるインスタンスオブジェクト(または同じインスタンスオブジェクト)を防止します。クラスのすべてのオブジェクトインスタンスで動作します。
2。メソッドの前に同期されたキーワードを使用することに加えて、同期されたキーワードはメソッドのブロックでも使用でき、このブロックのリソースで相互に排他的なアクセスのみが実行されることを示します。使用法は次のとおりです。Synchronized(this){/*block*/}(または同期(obj){/*block*/})、そのスコープは現在のオブジェクトです。
3.同期されたキーワードを継承することはできません。つまり、基本クラスの同期f(){}の方法は、継承クラスでf(){}を自動的に同期するのではなく、f(){}になります。継承クラスでは、その方法の1つが同期されていることを明示的に指定する必要があります。
同期(これ)のいくつかの理解(オブジェクトロックをよく説明し、このキーワードに注意してください)
1. 2つの同時スレッドが同じオブジェクトオブジェクトでこの同期(この)同期コードブロックにアクセスすると、1回以内に1つのスレッドのみを実行できます。別のスレッドは、コードブロックを実行する前に、現在のスレッドがこのコードブロックを実行するのを待つ必要があります。
2.ただし、1つのスレッドがオブジェクトの同期(この)同期コードブロックにアクセスすると、別のスレッドはそのオブジェクトの非同期(この)同期コードブロックにアクセスできます。
3.スレッドがオブジェクトの同期(この)同期コードブロックにアクセスすると、他のスレッドがオブジェクト内の他のすべての同期(この)同期コードブロックへのアクセスをブロックすることが特に重要です。
4. 3番目の例は、他の同期コードブロックにも適用されます。つまり、スレッドがオブジェクトの同期(この)同期コードブロックにアクセスすると、このオブジェクトのオブジェクトロックが取得されます。その結果、オブジェクトオブジェクトのすべての同期コード部分への他のスレッドアクセスが一時的にブロックされます。
5.上記のルールは、他のオブジェクトロックにも適用されます。
同期されたキーワードのテストを容易にするためにコードを追加します(簡単な変更)
public class testsynchronized {public void test1(){synchronized(this){int i = 5; while(i--> 0){system.out.println(thread.currentthread()。getname() + ":" + i); {thread.sleep(500)を試してください。 } catch(arturnedexception ie){}}}} public synchronized void test2(){int i = 5; while(i--> 0){system.out.println(thread.currentthread()。getname() + ":" + i); {thread.sleep(500)を試してください。 } catch(arturtedexception ie){}}} public synchronized void test3(){int i = 5; while(i--> 0){system.out.println(thread.currentthread()。getname() + ":" + i); {thread.sleep(500)を試してください。 } catch(arturtedexception ie){}}} public static void main(string [] args){final testsynchronized myt2 = new testsynchronized();最終的なtestsynchronized myt3 = new testsynchronized(); Thread test1 = new Thread(new runnable(){public void run(){myt2.test2();}}、 "test1");スレッドtest2 = newスレッド(new runnable(){public void run(){myt2.test3();}}、 "test3"); test1.start();; test2.start(); }}実行結果:
test1:4test1:3test1:2test1:1test1:0test3:4test3:3test3:2test3:1test3:0
以下に、JavaでのSychronizedの使用に焦点を当てます。これは、特に同期方法と、同期された方法と同期ブロックの2つの使用法を含む同期ブロック同期キーワードです。
1。同期された方法:同期されたキーワードをメソッド宣言に追加することにより、同期されたメソッドを宣言します。のように:
public同期void Accessval(int newval);
同期されたメソッドは、クラスメンバー変数へのアクセスを制御します。各クラスインスタンスはロックに対応し、各同期メソッドは、実行する前にメソッドを呼び出すクラスインスタンスのロックを取得する必要があります。それ以外の場合、それが属するスレッドがブロックされます。メソッドが実行されると、ロックのみが占有されます。ロックはメソッドから戻るまで放出されません。ブロックされたスレッドは、ロックを取得し、実行可能状態に再入力できます。このメカニズムは、同時に、クラスのインスタンスごとに、同期と宣言されたすべてのメンバー関数の1つが実行可能な状態であることを保証します(ほとんどの場合、クラスインスタンスに対応するロックを取得できるため)。
Javaでは、クラスインスタンスだけでなく、各クラスもロックに対応するため、クラスの静的メンバー変数へのアクセスを制御するために、static同期としてクラスの静的メンバー関数を宣言できます。
同期された方法の欠点:大規模な方法を同期していると宣言すると、効率に大きく影響します。通常、スレッドクラスのMethod run()が同期されていると宣言されている場合、スレッドの寿命を通じて実行されているため、このクラスの同期された方法で成功することはありません。もちろん、クラスメンバー変数にアクセスするコードを特別な方法に配置し、同期していると宣言し、メイン方法で呼び出すことでこの問題を解決できますが、Javaはより良いソリューション、つまり同期ブロックを提供します。
2。同期ブロック:同期キーワードを介して同期ブロックを宣言します。構文は次のとおりです。
同期(syncobject){//アクセス制御を許可するコード}同期されたブロックは、コードが実行される前にオブジェクトSyncobject(前述のように、クラスインスタンスまたはクラスになることができる)のロックを取得する必要があるコードブロックです。特定のメカニズムは、上記と同じです。任意のコードブロックでターゲットにすることができ、ロックされたオブジェクトはいつでも指定できるため、より柔軟です。
知らせ:
同期されたキーワードを使用する場合、同期されたプログラムブロックがオブジェクトロックを占有するため、同期したメソッドまたは同期ブロックで睡眠または収量のメソッドを可能な限り使用しないようにする必要があります。効率に深刻な影響を与えるだけでなく、論理的でもありません。
同様に、同期プログラムブロックのYeildメソッドを呼び出してCPUリソースを放棄することは意味がありません。ロックを占有し、他のミューテックススレッドは同期プログラムブロックにアクセスできないためです。もちろん、同期プログラムブロックに関連していないスレッドは、より多くの実行時間を取得できます。
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。