キーワード同期
同期されたキーは、関数内の関数とステートメントを変更できます。メソッドまたはオブジェクトに追加されるかどうかにかかわらず、それが取得するロックは、コードまたは機能をロックとして扱うのではなく、オブジェクトです。
1.同時スレッドが同じオブジェクトで同期した(この)同期コードブロックにアクセスすると、1つのスレッドのみが実行でき、他のスレッドは現在のスレッドが実行された後にのみ実行できます。
2。スレッドがオブジェクト内の同期(この)同期コードブロックにアクセスすると、他のスレッドは、このオブジェクトの他の非同期(この)コードブロックにアクセスできます。
3.ここで、スレッドがオブジェクトの同期(この)コードブロックにアクセスすると、他のスレッドがこのオブジェクトの他の同期(この)同期コードブロックにアクセスすることをブロックすることに注意する必要があります。
4.上記は、他の同期コードブロックにも適用できます。つまり、スレッドがオブジェクトの同期(この)同期コードブロックにアクセスすると、スレッドはオブジェクトのオブジェクトロックを取得します。さらに、各オブジェクト(つまり、クラスインスタンス)は、それぞれの同期(これ)が実行されるオブジェクトのロック(機能または変数)を取得する必要があります。属するメソッドが実行されると、ロックはメソッドから戻り、実行可能状態に再び入るまでのみ占有されます。このメカニズムは、同時に、各オブジェクトについて、最大で同期されたすべてのメンバー関数の1つが実行可能な状態であることを保証します(最大で1つのスレッドがオブジェクトのロックを取得できるため)。 。
同期された方法の短所:
同期されたものは、この同期メソッドを呼び出すオブジェクトをロックするため、つまりスレッドP1が異なるスレッドでこのメソッドを実行すると、相互除外を形成し、それによって同期の効果を達成します。ただし、このオブジェクトの別のクラスのオブジェクトは、同期されたキーワードを追加してこのメソッドを任意に呼び出すことができることに注意する必要があります。同期の本質は、P1の同期メソッドを取得したスレッドのみを適用することですこのケースは、メカニズムの制御を引き起こします。この状況を以下で詳しく説明します。
まず、同期されたキーワードを使用して2つのロックされたオブジェクトを導入しましょう。同期は、このクラスのすべてのオブジェクト(インスタンス)にオブジェクトロックまたはクラスロックを追加することができ、オブジェクトロックは指定されたオブジェクトのためにロックされています。このクラスのうち、このクラスの他のオブジェクトは、以前のオブジェクトをロックした同期メソッドを使用できます。
ここで説明する主な問題の1つは、「同じクラスと異なるインスタンスが同じ方法を呼び出すのか、同期の問題があるのか?」です。
同期の問題はリソースにのみ関連しており、リソースが静的であるかどうかに依存します。同じ静的データについては、同じ関数が同時にそれを読み書きするためのスレッドに属し、CPUはエラーを生成しませんあなた。 CPUの2つの異なるコアで2つの異なるコードが実行され、同時にメモリアドレスを書く場合でも、キャッシュメカニズムは最初にL2で1つをロックします。次に、別のコアと更新して共有すると、エラーがありません。そうしないと、IntelまたはAMDは無駄になります。
したがって、2つのコード共有と同じリソースまたは変数がない限り、データの矛盾はありません。さらに、同じクラスの異なるオブジェクトへの呼び出しは完全に異なるスタックを持ち、それらは完全に無関係です。
ここでは、例を使用してチケット販売プロセスを説明します。ここでは、共有リソースが残りのチケット数です。
パッケージcom.test; public classsafetest runnable {private statresafetest(string name){setna me(name){sell(); void sell(String name){num> 0){name + ":検出投票数が大きい") (約5秒で完了)。 ;} catch(e.printstacktrace() (「システム数:「 + num); args [] {try {new threadsafetest(li xx ").start(2000); {e.printstacktrace()}}上記のコードを実行すると、取得する出力は次のとおりです。
チケットコンダクターLi XX:テストチケットの数は0を超えています。 。 。チケットコンダクターキングX:テストチケットの数は0を超えています。 。 。チケット売り手li XX:請求書の印刷、チケット販売完了システム:現在の投票数:0チケット売り手王X:請求書の印刷、チケット販売完了システム:現在の投票数:-1警告:投票数はより低い0、負の数が表示されます
出力の結果に基づいて、残りの投票は-1であり、同期エラーの問題があることがわかります。この理由は、作成した2つのインスタンスオブジェクトが共有静的リソースの静的int num = 1を同時に変更したためです。次に、上記のコードのボックス内の修飾子静的を削除し、プログラムを実行して取得します。
チケットコンダクターLi XX:テストチケットの数は0を超えています。 。 。チケットコンダクターキングX:テストチケットの数は0を超えています。 。 。チケット販売者Li XX:請求書の印刷、チケット販売完了システム:現在のチケット数:0チケット売り手王X:請求書を印刷し、チケット販売完了システム:現在のチケット数:0
学位を変更した後、プログラムは問題なく実行されます。しかし、これは、複数のスレッドが共有リソースを同時に処理できるという予想に反します(静的な後、共有リソースから各インスタンスが所有するメンバー変数に変更することができます)。これは明らかに私たちが望むものではありません。
上記の2つのコードでは、採用する主なことはオブジェクトをロックすることです。前に言及した理由で、クラスの2つの異なるインスタンスが同じ共有リソースを変更すると、CPUはプログラムのみが自分のために決定するかどうかをデフォルトします。したがって、ターゲットが単なるインスタンスである場合、ロックの範囲が避けられない場合にのみ、同じクラスの異なるインスタンスを除外できます。クラスと共有リソースは同時に。
パッケージcom.test; public classsafetest runnable {private statresafetest(string name){setna me(name){sell(); static void sell(num> 0){name + ":検出投票数が大きい支払いの収集(約5秒)。 () .println( "system:" + num); string args {try {new StreadSaftEST( "Ticke sell li xx") ){e.printstacktrace()}}上記のようにプログラムを作成して、実行結果を取得します。
チケットコンダクターLi XX:テストチケットの数は0を超えています。 。 。チケット販売者Li XX:チケットの印刷、チケット販売完了システム:現在のチケット数:0チケット売り手王X:チケットなし、停止チケット販売
静的修飾子がsell()メソッドに追加され、ロックのオブジェクトがクラスのインスタンスが共有変数で動作する場合、クラスの他のインスタンスが操作をブロックします。これにより、期待どおりに必要な結果が得られます。
要約:
1.同期されたキーワードには、同期されたメソッドと同期ブロックの2つの用途があります。
2。Javaでは、クラスのインスタンスであるだけでなく、同期されたキーワードを使用する場合、次の点に注意することもできます。
1.同期されたキーワードを継承することはできません。同期はメソッドを定義するために使用できますが、同期はメソッド定義の一部に属していないため、同期されたキーワードを継承することはできません。親クラスのメソッドが同期されたキーワードを使用し、サブクラスもこのメソッドをオーバーライドする場合、デフォルトではサブクラスのメソッドが同期されておらず、サブクラスのみを使用するために表示する必要があります。もちろん、サブクラスの親クラスの対応するメソッドを呼び出すこともできますが、サブクラスのメソッドは同期されていませんが、サブクラスは親クラスの同期メソッドを呼び出します。同期している。のように、
同期されたキーワードをサブクラスに追加します。
class parent {public synchronized void method(){}} class child extends parent {public synchronized void method(){}}親クラスの方法を呼び出します:
class parent {public synchronized void method(){}} class extends public void method(){super.method()}; 2。インターフェイスメソッドを定義するときに、同期されたキーワードを使用できません。
3.コンストラクターは同期されたキーワードを使用できませんが、同期されたブロックを同期に使用できます。
4.同期位置は自由に配置できますが、メソッドの返品タイプの後ろに配置することはできません。
5.同期されたキーワードを使用して、次のコードが正しくないなど、変数を同期することはできません。
public Synchronized int n = 0;
6.同期されたキーワードを使用することは最も安全な同期方法ですが、大量に使用する場合、不必要なリソース消費とパフォーマンスの損失も引き起こします。表面的には、同期はメソッドをロックしますが、たとえば、同期されたキーワードは、メソッドのいずれかを実行する場合、他のメソッドを実行できません。実行された。静的方法は、非静的な方法に似ています。ただし、静的な方法と非静的な方法は互いに影響しません。次のコードを参照してください。
public class mythread1 {public station void method(system) ");} public synchronized void method2(){method(" non-static method2 method ");} public static同期void method3(){method(" static method3 method ");} public static同期void method4(){method ( "static method4 method"); public void run(){getClass()。 )スロー{mythread1 = new mythread1(); );操作結果は次のとおりです。
非静的方法1メソッド静的メソッド3メソッド
上記の実行結果から、Method2とMethod4がMethod1とMethod3が完了するまで実行されないことがわかります。したがって、同期を使用してクラスの非静的な方法を定義すると、このクラスのすべての同期された定義された非静的メソッドに影響するという結論を導き出すことができます。このクラスでは、同期によって定義された静的メソッド。これは、レコードが変更された場合、テーブル全体をロックします。したがって、この同期方法を大量に使用すると、プログラムのパフォーマンスが大幅に低下します。
共有リソースへのより安全なアクセスのためのヒント:
1.パブリック/保護されたインスタンス変数を定義する代わりに、プライベート + Getメソッドのインスタンス変数を定義します。変数がパブリックとして定義されている場合、オブジェクトは外部世界の同期法の制御を直接取得して変更できます。これは、Javabeanの標準的な実装の1つでもあります。
2。インスタンス変数が配列やアレイリストなどのオブジェクトである場合、上記の方法はまだ安全ではありません。なぜなら、外の世界がGETメソッドを介してインスタンスオブジェクトを参照し、別のオブジェクトに向けてから、それを指してから、プライベート変数も変更されていますが、非常に危険ではないでしょうか?この時点で、このプライベートオブジェクトのメソッドを取得し、clone()のみを取得するために同期を追加する必要があります。このようにして、発信者が取得するのは、オブジェクトコピーへの参照だけです。
オブジェクトモニターを取得する3つの方法(lock)とnotify()
スレッドメソッドでは、wait()およびnotify()を呼び出して、オブジェクトオブジェクトを指定する必要があり、スレッドにはオブジェクトオブジェクトのモニターが必要です。オブジェクトモニターを取得する最も簡単な方法は、オブジェクト上の同期キーワードを使用することです。 wait()メソッドを呼び出した後、スレッドはオブジェクトロックを放出し、スリープ状態を入力します。他のスレッドがnotify()メソッドを呼び出す場合、同じオブジェクトオブジェクトを使用する必要があります。
オブジェクトによってロックされた複数のメソッドの場合、そのうちの1つはnotify()メソッドを呼び出すときに目を覚ますように選択され、notifyall()はすべての待機スレッドを目覚めさせます。
パッケージnet.mindview.util; import javax.swing.jframe; public static void main(string [] args){system( "hello world!"); frame.setdefaultcloseoperation(exit_on_close); 300、100); {waitandnotifyjframe.this(); .add(start); jbutton Pause = new Jbutton( "Pause"){ActionEvent e){(t!= null){t。iswait= true;}}); (一時停止); jbutton end = new jbutton( "end"){actionevent e){if(t!= null){t.interrupt(); t = null;}}); .add(); = f; false = 0; if(iswait)wait();上記の例ボックスのコードのように、同期コードブロックが削除された場合、実行はjava.lang.illegalmonitorStateExceptionの例外をスローします。
JDKを見ると、この例外の理由は、現在のスレッドがこのオブジェクトモニターの所有者ではないことがあることがわかります。
この方法は、このオブジェクトモニターの所有者であるスレッドでのみ呼び出されます。このオブジェクトモニターの所有者にすることができます。
1。次のような、このオブジェクトの同期インスタンスメソッドを実行することにより。
public同期void n(){notify(); 2。次のような、このオブジェクトで同期される同期されたステートメントの本文を実行することにより。
public void n(){synchronized(this){notify()} 3。クラスタイプのオブジェクトの場合、このクラスの同期静的メソッドを実行できます。
静的メソッドを呼び出すとき、必ずしもインスタンスオブジェクトを作成するわけではありません。したがって、これを使用して静的メソッドを同期させるため、notic()メソッドは静的メソッドではないため、Classオブジェクトを使用する必要があります。説明する別の例:
パブリッククラスの同期実装実装可能{private static boolean flag = true; // class object synchronization method one://静的修正の同期方法に注意を払ってください。 i = 0; //クラスオブジェクトの同期方法2:private void testsyncblock(){// display getクラスをモニターとして使用します。静的同期メソッドが暗黙的にクラスモニターを取得するのと同じです。同期(synchronized ( "testsyncblock:" + i);したがって、異なるスレッドは異なる方法を実行し、この方法でのみ異なるロック効果を見ることができます。 if(false); = new SynchizedStatic();上記のコードは、2つの同期メソッドを実行して、0から99に同時に印刷しますブロック。 2つの方法は似ています。メソッド1とメソッド2は両方とも相互に排他的です。したがって、プログラムの実行結果は次のとおりです。
testsyncmethod:0testsyncmethod:1 ... ... testsyncmethod:99testsyncblock:0 ... ... testsyncblock:99
ただし、範囲がないため、方法2の同期クラスを置き換えると、これらの2つの方法は相互除外を形成せず、以下に示すように、プログラムの出力結果も実行されます。
testsyncblock:0testsyncmethod:0testsyncblock:1testsyncmethod:1 ... ... testsyncmethod:99testsyncblock:99
ロックには2つのスコープがあり、1つはクラスのオブジェクトであり、もう1つはクラス自体です。上記のコードでは、ロックの範囲をクラスにするための2つの方法が与えられているため、同じクラスの異なるオブジェクト間で同期を完了することができます。
上記を要約するには、次のポイントに注意する必要があります。
1。wait()、notify()、およびnotifyall()はすべて、オブジェクトモニターを持っているという前提で実行する必要があります。
2。複数のスレッドが同時に1つのオブジェクトを待つことができます。
3。Notify()は、スレッドが待機していない場合、何もしないスレッドをランダムに覚ますことです。
4. notify()によって目覚めたスレッドは、notify()が実行された直後に目覚めませんが、notify()スレッドがオブジェクトモニターをリリースした後にのみです。
5.これらのオブジェクトの方法は、スレッドの睡眠や割り込み方法とは程遠いので、混同しないでください。