Java言語キーワードを使用してメソッドまたはコードブロックを変更すると、最大で1つのスレッドが同時にコードを実行することを保証できます。
1. 2つの同時スレッドが同じオブジェクトオブジェクトでこの同期(この)同期コードブロックにアクセスすると、1回以内に1つのスレッドのみを実行できます。別のスレッドは、コードブロックを実行する前に、現在のスレッドがこのコードブロックを実行するのを待つ必要があります。
2.ただし、1つのスレッドがオブジェクトの同期(この)同期コードブロックにアクセスすると、別のスレッドはそのオブジェクトの非同期(この)同期コードブロックにアクセスできます。
3.スレッドがオブジェクトの同期(この)同期コードブロックにアクセスすると、他のスレッドがオブジェクト内の他のすべての同期(この)同期コードブロックへのアクセスをブロックすることが特に重要です。
4. 3番目の例は、他の同期コードブロックにも適用されます。つまり、スレッドがオブジェクトの同期(この)同期コードブロックにアクセスすると、このオブジェクトのオブジェクトロックが取得されます。その結果、オブジェクトオブジェクトのすべての同期コード部分への他のスレッドアクセスが一時的にブロックされます。
5.上記のルールは、他のオブジェクトロックにも適用されます。
例を挙げてください:
1. 2つの同時スレッドが同じオブジェクトオブジェクトでこの同期(この)同期コードブロックにアクセスすると、1回以内に1つのスレッドのみを実行できます。別のスレッドは、コードブロックを実行する前に、現在のスレッドがこのコードブロックを実行するのを待つ必要があります。
パッケージths; public class thread1を実装します{public void run(){synchronized(this){for(int i = 0; i <5; i ++){system.out.println(thread.currentthread()。getName() + "同期ループ" + i); }}} public static void main(string [] args){thread1 t1 = new shood1(); Thread ta = new Thread(t1、 "a");スレッドTB = newスレッド(T1、 "B"); ta.start(); tb.start(); }}結果:
同期されたループ0
同期されたループ1
同期ループ2
同期されたループ3
同期ループ4
B同期ループ0
B同期ループ1
B同期ループ2
B同期ループ3
B同期ループ4
2.ただし、1つのスレッドがオブジェクトの同期(この)同期コードブロックにアクセスすると、別のスレッドはそのオブジェクトの非同期(この)同期コードブロックにアクセスできます。
パッケージths; public class thread2 {public void m4t1(){synchronized(this){int i = 5; while(i--> 0){system.out.println(thread.currentthread()。getname() + ":" + i); {thread.sleep(500)を試してください。 } catch(arturtedexception ie){}}}} public void m4t2(){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 swreet2 myt2 = new shood2();スレッドT1 = newスレッド(new runnable(){public void run(){myt2.m4t1();}}、 "t1");スレッドT2 = newスレッド(new runnable(){public void run(){myt2.m4t2();}}、 "t2"); t1.start(); t2.start(); }}結果:
T1:4
T2:4
T1:3
T2:3
T1:2
T2:2
T1:1
T2:1
T1:0
T2:0
3.スレッドがオブジェクトの同期(この)同期コードブロックにアクセスすると、他のスレッドがオブジェクト内の他のすべての同期(この)同期コードブロックへのアクセスをブロックすることが特に重要です。
// thread2.m4t2()メソッドを変更する方法:public void m4t2(){synchronized(this){int i = 5; while(i--> 0){system.out.println(thread.currentthread()。getname() + ":" + i); {thread.sleep(500)を試してください。 } catch(arternedexception ie){}}}}結果:
T1:4
T1:3
T1:2
T1:1
T1:0
T2:4
T2:3
T2:2
T2:1
T2:0
4. 3番目の例は、他の同期コードブロックにも適用されます。つまり、スレッドがオブジェクトの同期(この)同期コードブロックにアクセスすると、このオブジェクトのオブジェクトロックが取得されます。その結果、オブジェクトオブジェクトのすべての同期コード部分への他のスレッドアクセスが一時的にブロックされます。
// thread2.m4t2()メソッドを次のように変更します。 while(i--> 0){system.out.println(thread.currentthread()。getname() + ":" + i); {thread.sleep(500)を試してください。 } catch(arternedexception ie){}}}結果:
T1:4
T1:3
T1:2
T1:1
T1:0
T2:4
T2:3
T2:2
T2:1
T2:0
5.上記のルールは、他のオブジェクトロックにも適用されます。
パッケージths; public class thread3 {class inenter {private void m4t1(){int i = 5; while(i-> 0){system.out.println(thread.currentthread()。getname() + ":inner.m4t1()=" + i); {thread.sleep(500)を試してください。 } catch(arternedexception ie){}}} private void m4t2(){int i = 5; while(i-> 0){system.out.println(thread.currentthread()。getname() + ":inner.m4t2()=" + i); {thread.sleep(500)を試してください。 } catch(arternedexception ie){}}}} private void m4t1(innerine){synchronized(inner){// Object lock inner.m4t1();を使用します。 } private void m4t2(inenter inener){inner.m4t2(); } public static void main(string [] args){final thread3 myt3 = new shood3();最終的な内側の内側= myt3.new inner();スレッドT1 = newスレッド(new runnable(){public void run(){myt3.m4t1(inner);}}、 "t1");スレッドt2 = newスレッド(new runnable(){public void run(){myt3.m4t2(inner);}}、 "t2"); t1.start(); t2.start(); }}結果:
スレッドT1は内側のオブジェクトロックを取得しますが、スレッドT2は同じ内側の非同期部分にアクセスするためです。したがって、2つのスレッドは互いに干渉しません。
T1:inner.m4t1()= 4
T2:inner.m4t2()= 4
T1:inner.m4t1()= 3
T2:inner.m4t2()= 3
T1:inner.m4t1()= 2
T2:inner.m4t2()= 2
T1:inner.m4t1()= 1
T2:inner.m4t2()= 1
T1:inner.m4t1()= 0
T2:inner.m4t2()= 0
inner.m4t2()の前に同期して同期します:
private同期void m4t2(){int i = 5; while(i-> 0){system.out.println(thread.currentthread()。getname() + ":inner.m4t2()=" + i); {thread.sleep(500)を試してください。 } catch(arternedexception ie){}}}結果:
スレッドT1とT2は、同じ内部オブジェクトの2つの無関係な部分にアクセスしますが、T1は最初に内側へのオブジェクトロックを取得するため、M4T2()は内側の同期方法であるため、T2の内側へのアクセスもブロックされます。
T1:inner.m4t1()= 4
T1:inner.m4t1()= 3
T1:inner.m4t1()= 2
T1:inner.m4t1()= 1
T1:inner.m4t1()= 0
T2:inner.m4t2()= 4
T2:inner.m4t2()= 3
T2:inner.m4t2()= 2
T2:inner.m4t2()= 1
T2:inner.m4t2()= 0
第2条:
同期されたキーワード。これには、同期メソッドと同期ブロックの2つの使用法が含まれます。
1。同期された方法:同期されたキーワードをメソッド宣言に追加することにより、同期されたメソッドを宣言します。のように:
public同期void Accessval(int newval);
同期されたメソッドは、クラスメンバー変数へのアクセスを制御します。各クラスインスタンスはロックに対応し、各同期メソッドは、実行する前にメソッドを呼び出すクラスインスタンスのロックを取得する必要があります。それ以外の場合、それが属するスレッドがブロックされます。メソッドが実行されると、ロックのみが占有されます。ロックはメソッドから戻るまで放出されません。ブロックされたスレッドは、ロックを取得し、実行可能状態に再入力できます。このメカニズムは、同時に、クラスのインスタンスごとに、同期と宣言されたすべてのメンバー関数の1つが実行可能な状態であることを保証します(ほとんどの場合、クラスインスタンスに対応するロックを取得できるため)。
Javaでは、クラスインスタンスだけでなく、各クラスもロックに対応しているため、クラスの静的メンバー変数へのアクセスを制御するために同期してクラスの静的メンバー関数を宣言できます。
同期された方法の欠点:大規模な方法を同期していると宣言すると、効率に大きく影響します。通常、スレッドクラスのMethod run()が同期されていると宣言されている場合、スレッドの寿命を通じて実行されているため、このクラスの同期された方法で成功することはありません。もちろん、クラスメンバー変数にアクセスするコードを特別な方法に配置し、同期していると宣言し、メイン方法で呼び出すことでこの問題を解決できますが、Javaはより良いソリューション、つまり同期ブロックを提供します。
2。同期ブロック:同期キーワードを介して同期ブロックを宣言します。構文は次のとおりです。
同期(syncobject){//アクセス制御を許可するコード}同期されたブロックは、コードが実行される前にオブジェクトSyncobject(前述のように、クラスインスタンスまたはクラスになることができる)のロックを取得する必要があるコードブロックです。特定のメカニズムは、上記と同じです。任意のコードブロックでターゲットにすることができ、ロックされたオブジェクトはいつでも指定できるため、より柔軟です。
同期(This)<Br /> 1のいくつかの理解。 2つの同時スレッドが同じオブジェクトでこの同期(この)同期コードブロックにアクセスすると、1回以内に1つのスレッドのみを実行できます。別のスレッドは、コードブロックを実行する前に、現在のスレッドがこのコードブロックを実行するのを待つ必要があります。
2.ただし、1つのスレッドがオブジェクトの同期(この)同期コードブロックにアクセスすると、別のスレッドはそのオブジェクトの非同期(この)同期コードブロックにアクセスできます。
3.スレッドがオブジェクトの同期(この)同期コードブロックにアクセスすると、他のスレッドがオブジェクト内の他のすべての同期(この)同期コードブロックへのアクセスをブロックすることが特に重要です。
4. 3番目の例は、他の同期コードブロックにも適用されます。つまり、スレッドがオブジェクトの同期(この)同期コードブロックにアクセスすると、このオブジェクトのオブジェクトロックが取得されます。その結果、オブジェクトオブジェクトのすべての同期コード部分への他のスレッドアクセスが一時的にブロックされます。
5.上記のルールは、他のオブジェクトロックにも適用されます。
Javaで同期した使用方法
たとえば、オブジェクトは大きな家のようなもので、ドアは常に開いています。家には多くの部屋があります(つまり、方法)。
これらの部屋はロックされており(同期された方法)、ロックされていません(通常の方法)。ドアに鍵があり、すべてのロックされた部屋を開くことができます。
さらに、オブジェクトメソッドを呼び出したいすべてのスレッドを、この家の部屋に入りたい人と比較します。非常に多くのことしかありません。これらのことがどのように機能するか見てみましょう。
ここでは、最初に前提条件を明確にします。オブジェクトには少なくとも1つの同期メソッドがあります。そうでなければ、このキーのポイントは何ですか?もちろん、私たちにとってそのようなトピックはありません。
男が閉じ込められた部屋に入りたかった。彼は家のドアに来て、そこに鍵を見ました(それは、他の誰もロックされた部屋をまだ使いたくないことを意味します)。そこで彼は立ち上がって鍵を手に入れ、計画どおりの部屋を使用しました。彼は毎回ロックされた部屋を使用した後すぐにキーを返すことに注意してください。たとえ彼が2つのロックされた部屋を連続して使用したいとしても、彼はそれらを取得するためにキーを返します。したがって、通常の場合にキーを使用するという原則は、「使用すると借りて、使用したらすぐに返品」です。
現時点では、他の人は制限なしにロックされていない部屋を使用できます。 1人は1つの部屋を使用でき、2人は制限なしに1つの部屋を使用できます。しかし、誰かが鍵のかかった部屋に入りたいなら、彼はゲートに駆け寄って見てみる必要があります。もちろん、キーがある場合は、去ります。持っていない場合は、待つことしかできません。多くの人がこのキーを待っている場合、それが返された後、誰が最初にキーを手に入れますか?保証されていません。前の例の男のように、2つのロックされた部屋を連続して使用したいと思っていますが、中央に鍵を待っている他の人がいる場合、この男が再びそれを手に入れるという保証はありませんでした。 (Java仕様は、Thread.Sleep()が休息後に走るのにかかる時間、同じ優先順位を持つスレッドが最初に実行されるまでにかかる時間など、多くの場所で保証されていないことを明確に述べています。 1つの条件ですが、多くの記事に基づいています。
判断条件が多すぎるため、あなたがそれを言うと、それはJavaの促進に影響を与える可能性があるか、知的財産保護による可能性があります。太陽は私に約束を与え、それを乗り越えました。それには何の問題もありません。しかし、これらの不確実性は完全に不確実ではないと思います。コンピューター自体が指示に従って実行されるためです。現象がランダムに見える場合でも、実際には定期的です。コンピューターを研究した人なら誰でも、コンピューターの乱数の科学名は擬似ランダム数であり、特定の方法を使用している人々によって書かれていることを知っており、ランダムに見えるだけです。さらに、おそらくそれは、それを確保するのが難しすぎて、あまり意味がないからです。 ))
同期コードブロックを見てみましょう。同期方法とはわずかな違いがあります。
1。サイズに関しては、同期コードブロックは同期法よりも小さくなります。同期コードブロックは、ロックされた画面で区切られたロック解除された部屋のスペースと考えることができます。
2。同期コードブロックは、特定の他のオブジェクトを取得する鍵を人為的に指定することもできます。画面のロックを解除するキーを指定するのと同じように、この部屋のキーを使用できます。また、別の家の鍵がそれを開くことができることを指定することもできます。このようにして、そのキーを持ち込み、その家の鍵を使用してこの家の鍵のかかった画面を開くために別の家に走る必要があります。
あなたが手に入れた他の家の鍵は、その家に錠前に入る部屋に入る他の人に影響を与えないことを忘れないでください。
同期コードブロックを使用する理由まずこのようなものであるべきだと思います。まず、プログラムの同期部分は操作効率に大きな影響を与え、通常、最初にローカル変数を作成し、次に操作、ディスプレイなどのこれらの変数に対していくつかの操作を行うことです。同期でカバーされるコードが多いほど、効率への影響は深刻になります。したがって、私たちは通常、その影響を狭めようとします。
それをする方法は?コードブロックを同期します。操作などの1つの方法で同期する場所のみを同期します。
さらに、キーを指定できる同期コードブロックの機能には、追加の利点があります。つまり、一定期間内にオブジェクトのキーを占めることができます。前述の通常の状況でキーを使用する原則を覚えていますか?今は普通の状況ではありません。取得したキーは返されることはありませんが、同期コードブロックを終了するときにのみ返されます。
また、2つのロックされた部屋を連続して使用して例を挙げたいと思っていた前の男を使用しました。使用後、別のものを使用し続けるにはどうすればよいですか?同期コードブロックを使用します。最初に別のスレッドを作成し、同期コードブロックを作成し、そのコードブロックのロックを家のキーに向けます。次に、そのスレッドを起動します。そのコードブロックを入力するときに家の鍵をつかむことができる限り、そのコードブロックを終了するまで保持できます。言い換えれば、この部屋のすべてのロックされた部屋を横断したり、睡眠をとったりすることもできます(10*60*1000)、ドアにこのキーを待っている1,000個のスレッドがまだあります。とても楽しい。
ここでは、Sleep()メソッドとキーとの相関について説明します。キーを取得した後にスレッドがスリープ()を強制され、同期コンテンツが完了していない場合、キーはまだそこにあります。キーは再び実行され、すべての同期コンテンツを完了するまで返されません。その男は仕事にうんざりしていたので、彼は休憩を取りに行き、彼がやろうとしていることを終えなかったことを忘れないでください。部屋に入って混乱する他の人を避けるために、彼は眠っているときでさえ、彼の体に唯一の鍵を着なければなりません。
最後に、何人かの人々が尋ねるかもしれません、なぜあなたはキーとドアの代わりに開くためにキーが必要なのですか?これは純粋に複雑さのためだと思います。もちろん、1つのキーと1つのドアはより安全ですが、多くの問題が含まれます。キーの生成、ストレージ、取得、返品など。その複雑さは、同期法の増加とともに幾何学的なシーケンスが増加する可能性があり、効率に深刻な影響を与えます。これもトレードオフです。安全性を少し増やすことがどれほど望ましくないか、その結果、効率が大幅に減少します。
同期の簡単な例
public class textthread {public static void main(string [] args){txtthread tt = new txtthread();新しいスレッド(tt).start();新しいスレッド(tt).start();新しいスレッド(tt).start();新しいスレッド(tt).start(); }} class txtthread runnable {int num = 100; string str = new String(); public void run(){synchronized(str){while(num> 0){try {thread.sleep(1); } catch(例外e){e.getmessage(); } system.out.println(thread.currentThread()。getName() + "これは" + num--); }}}}上記の例では、時間差を作成するために、つまりエラーを作成する機会、スレッド(10)が使用されます。
Javaのマルチスレッドのためのサポートと同期メカニズムは非常に人気があります。同期されたキーワードを使用すると、マルチスレッド共有データの同期の問題を簡単に解決できるようです。正確に何?また、結論を出す前に、同期されたキーワードの役割を深く理解する必要があります。
一般に、同期されたキーワードは、関数の修飾子として、または関数内のステートメントとして使用できます。これは、通常言及されている同期方法と同期ステートメントブロックです。より慎重に分類すると、同期して、インスタンス変数、オブジェクト参照、静的関数、クラスリテラル(クラス名リテラル定数)に作用できます。
さらに詳しく説明する前に、いくつかのポイントを明確にする必要があります。
A.同期されたキーワードがメソッドまたはオブジェクトに追加されるかどうかにかかわらず、それが取得するロックは、コードまたは機能をロックとして扱うのではなく、オブジェクトです。
彼のスレッドへのオブジェクトアクセス。
B.各オブジェクトには、それに関連付けられた1つのロックのみがあります。
C.同期を実装するには、コストとして多くのシステム間頭を必要とし、デッドロックを引き起こす可能性があるため、不必要な同期制御を避けるようにしてください。
次に、コード上のさまざまな場所を使用して同期した影響について説明しましょう。
P1とP2が同じクラスの異なるオブジェクトであると仮定すると、このクラスは次の状況で同期ブロックまたは同期方法を定義し、P1とP2はそれらを呼び出すことができます。
1。同期が関数修飾子として使用される場合、例コードは次のとおりです。
public synchronized void methodaaa(){//…。}これは同期方法です。では、この時点でどのオブジェクトが同期されてロックされていますか?ロックするのは、この同期メソッドオブジェクトを呼び出すことです。つまり、オブジェクトP1が異なるスレッドでこの同期方法を実行する場合、同期の効果を実現するために、それらの間に相互除外が形成されます。ただし、このオブジェクトが属するクラスによって生成された別のオブジェクトP2は、同期されたキーワードを追加して、このメソッドを任意に呼び出すことができます。
上記の例コードは、次のコードと同等です。
public void methodaaa(){synchronized(this)//(1){//…..}}}(1)これはその時点でどういう意味ですか?これは、P1などのこの方法を呼び出すオブジェクトを指します。同期方法は、本質的にオブジェクト参照に同期して適用することがわかります。 P1オブジェクトロックを取得したスレッドのみがP1同期メソッドを呼び出すことができます。 P2の場合、P1ロックはそれとは何の関係もありません。このプログラムは、この状況での同期メカニズムの制御を取り除き、データの混乱を引き起こす可能性があります。
2。ブロックを同期すると、サンプルコードは次のとおりです。
public void method3(some object so){同期(so){//…..}}}この時点で、ロックはSOのオブジェクトです。ロックを取得した人は誰でも、制御するコードを実行できます。ロックとして明確なオブジェクトがある場合、このようなプログラムを書くことができますが、ロックとしてクリアオブジェクトがなく、コードを同期させるだけで、ロックとして動作する特別なインスタンス変数(オブジェクトである必要があります)を作成できます。
クラスfooを実装してrunnable {private byte [] lock = new byte [0]; //特別なインスタンス変数public void methoda(){synchronized(lock){//…}} //…..}注:ゼロ長バイト配列オブジェクトは、コンパイルされたバイトコードを作成するためのどのオブジェクトよりも経済的です。ゼロ長バイト[]オブジェクトを生成するには3つのオプコードのみが必要です。
3。同期して静的関数を使用すると、例のコードは次のとおりです。
class foo {public synchronized static void methodaaa()//同期静的関数{//…。 } public void methodbbb(){synchronized(foo.class)// class literal(class name literal constant)}}}コードのmethodbbb()メソッドは、ロックとしてクラスリテラルを使用します。同期した静的関数と同じ効果があります。得られたロックは非常に特別です。これは、現在このメソッドを呼び出すオブジェクトが属するクラスです(クラス、このクラスによって生成される特定のオブジェクトではありません)。
本「Execful Java」では、同期ロックとしてfoo.classとp1.getclass()を使用することは異なり、p1.getclass()を使用してこのクラスをロックする目的を達成することができないことを覚えています。 P1は、FOOクラスによって生成されたオブジェクトを指します。
クラスが同期静的関数Aと同期インスタンス関数Bを定義する場合、ロックが異なるため、複数のスレッドで2つのメソッドAとBにアクセスするときに、このクラスの同じオブジェクトOBJが同期を構成しないと推測できます。方法AのロックはオブジェクトOBJであり、BのロックはOBJが属するクラスです。
概要は次のとおりです。
どのオブジェクト同期ロックを見つけることで、より安全なマルチスレッドプログラムを設計するのに役立ちます。共有リソースへの同期アクセスをより安全にするためのいくつかのヒントもあります。
1.パブリック/保護されたインスタンス変数の代わりに、プライベート +そのGETメソッドのインスタンス変数を定義します。変数がpublicとして定義されている場合、オブジェクトは同期法の制御をバイパスし、直接取得して変更できます。これは、Javabeanの標準的な実装方法の1つでもあります。
2。インスタンス変数が配列や配列リストなどのオブジェクトである場合、上記の方法はまだ安全ではありません。外部オブジェクトがGETメソッドを介してインスタンスオブジェクトを参照して別のオブジェクトに向けた場合、プライベート変数は変更されます。この時点で、GETメソッドに同期して追加し、このプライベートオブジェクトのクローン()のみを返すようにする必要があります。
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。