1。同期問題が発生しました
スレッドの同期は、複数のスレッドがデータオブジェクトにアクセスしたときにデータの損傷を防ぐためです。
たとえば、ThreadsとThreadBの両方が同じFOOオブジェクトを操作し、FOOオブジェクト上のデータを変更します。
パッケージcn.thread; public class foo {private int x = 100; public int getx(){return x; } public int fix(int y){x = x -y; xを返します。 }}パッケージcn.thread; public class myrunnable runnable {private foo foo = new foo(); public static void main(string [] args){myrunnable run = new myRunnable();スレッドta = newスレッド(run、 "thread-a");スレッドTB = newスレッド(run、 "thread-b"); ta.start(); tb.start(); } public void run(){for(int i = 0; i <3; i ++){this.fix(30); {thread.sleep(1); } catch(arturnedexception e){e.printstacktrace(); } system.out.println(thread.currentThread()。getName() + ":現在のfoo object =" + foo.getx()); }} public int fix(int y){return foo.fix(y); }}実行結果:
スレッド-B:現在のfooオブジェクトのx値= 40
スレッドA:現在のfooオブジェクトのx値= 40
スレッド-B:現在のfooオブジェクトのx値= -20
スレッドA:現在のfooオブジェクトのx値= -20
スレッド-B:現在のfooオブジェクトのx値= -80
スレッドA:現在のfooオブジェクトのx値= -80
結果から、そのような出力値は明らかに不合理であることがわかりました。その理由は、2つのスレッドがデータを制御せずにFOOオブジェクトにアクセスしてデータを変更するためです。
結果の合理性を維持したい場合は、1つの目標を達成する必要があります。これは、FOOへのアクセスを制限することであり、一度に1つのスレッドのみにアクセスできます。これにより、FOOオブジェクトのデータの合理性が確保されます。
特定のJavaコードでは、2つの操作を完了する必要があります。
プライベートとして競争によって訪問されるリソースクラスのFOO変数Xを特定します。
変数を変更するコードを同期し、同期されたキーワードを使用してメソッドまたはコードを同期させます。
パッケージcn.thread; public class foo2 {private int x = 100; public int getx(){return x; } //同期メソッドpublic synchronized int fix(int y){x = x -y; system.out.println( "swrey" + thread.currentthread()。getName() + "run end、decaid" " + y +" "、現在の値は:" + x); xを返します。 } // //同期コードブロック// public int fix(int y){// synchronized(this){// x = x -y; // system.out.println( "thread" + thread.currentthread()。パッケージcn.thread; public class myrunnable2 {public static void main(string [] args){myrunnable2 run = new myrunnable2(); foo2 foo2 = new foo2(); mythread t1 = run.new mythread( "thread a"、foo2、10); mythread t2 = run.new mythread( "スレッドB"、foo2、-2); mythread t3 = run.new mythread( "スレッドC"、foo2、-3); mythread t4 = run.new mythread( "スレッドD"、foo2、5); t1.start(); t2.start(); t3.Start(); t4.start(); } class mythreadはスレッドを拡張します{private foo2 foo2; / **現在の値*/ private int y = 0; mythread(string name、foo2 foo2、int y){super(name); this.foo2 = foo2; this.y = y; } public void run(){foo2.fix(y); }}}スレッドAランエンド、「10」が減少し、現在の値は次のとおりです。
スレッドCは実行および終了し、「-3」を減らし、現在の値は93です
スレッドBは最後に実行され、「-2」を減らし、現在の値は95です
スレッドDは実行および終了し、「5」を減らし、現在の値は90です
2。同期とロック
1。ロックの原理
Javaの各オブジェクトには、ロックが組み込まれています。
プログラムが非静的同期化された同期方法で実行されると、実行中のコードクラスの現在のインスタンスに関連付けられているロック(このインスタンス)。オブジェクトを取得するロックは、[ロックの取得、オブジェクトのロック、オブジェクトのロック、またはオブジェクトの同期とも呼ばれます。
オブジェクトロックは、プログラムが同期化された同期方法またはコードブロックに実行される場合にのみ機能します。
オブジェクト用のロックは1つだけです。したがって、スレッドがロックを取得した場合、最初のスレッドがロックを解放(または返す)まで他のスレッドがロックを取得することはできません。これはまた、ロックが解放されるまで、オブジェクトに同期されたメソッドまたはコードブロックを他のスレッドに入力できないことを意味します。
ロックのリリースとは、ロックスレッドが同期化された同期方法またはコードブロックを終了することを意味します。
ロックと同期については、いくつかの重要なポイントがあります。
1)メソッドのみを同期できますが、変数とクラスを同期することはできません。
2)各オブジェクトには1つのロックのみがあります。同期に関しては、何が明確になるはずですか?つまり、どのオブジェクトが同期されていますか?
3)クラス内のすべてのメソッドを同期する必要はありません。クラスは、同期方法と非同期の両方の方法を持つことができます。
4)2つのスレッドが1つのクラスで同期されたメソッドを実行し、2つのスレッドが同じインスタンスを使用してメソッドを呼び出す場合、1つのスレッドのみがメソッドを一度に実行でき、もう1つのスレッドはロックが解放されるまで待つ必要があります。つまり、スレッドがオブジェクトのロックを取得した場合、他のスレッドは(そのオブジェクトの)クラスに任意の同期方法を入力できません。
5)スレッドに同期と非同期方法がある場合、非同期メソッドは、ロックによって制限されることなく、複数のスレッドで自由にアクセスできます。
6)スレッドが眠るとき、それが保持するロックは解放されません。
7)スレッドは複数のロックを取得できます。たとえば、1つのオブジェクトの同期方法で別のオブジェクトの同期方法を呼び出すと、2つのオブジェクトの同期ロックが取得されます。
8)同期は同時性を損ない、同期範囲を可能な限り狭める必要があります。同期は、メソッド全体を同期するだけでなく、メソッドのいくつかのコードブロックを同期することもできます。
9)同期コードブロックを使用する場合、同期するオブジェクト、つまりどのオブジェクトのロックを取得するかを指定する必要があります。例えば:
public int fix(int y){synchronized(this){x = x -y; } return x;}もちろん、同期方法も非同期方法として書き直すことができますが、機能はまったく同じです。たとえば
public synchronized int getx(){return x ++;}そして
public int getx(){synchronized(this){return x ++; }}効果はまったく同じです。
3。静的メソッド同期
静的メソッドを同期するには、クラスオブジェクト全体、つまりこのクラス(xxx.class)にロックが必要です。
例えば:
public static synchronized int setName(string name){xxx.name = name;}
に相当
public static int setName(string name){synchronized(xxx.class){xxx.name = name; }}4。スレッドがロックを取得できない場合はどうなりますか
スレッドが同期メソッドを入力しようとし、そのロックが占有されている場合、スレッドはオブジェクト上でブロックされます。基本的に、スレッドはオブジェクトのプールに入り、ロックが解放されてスレッドが再び実行できるようになるまで待つ必要がある場所を待つ必要があります。
ブロッキングを検討するときは、ロックに使用されているオブジェクトに注意を払ってください。
1。同じオブジェクトの非静的同期メソッドを呼び出すスレッドは、互いにブロックされます。別のオブジェクトの場合、各スレッドには独自のオブジェクトロックがあり、スレッドは互いに干渉しません。
2。同じクラスで静的同期メソッドを呼び出すスレッドは互いにブロックされ、それらはすべて同じクラスオブジェクトにロックされています。
3.静的な同期方法と非静的同期方法は互いにブロックすることはありません。これは、静的方法がクラスオブジェクトにロックされているため、このクラスのオブジェクトにロックされているためです。
4.同期されたコードブロックの場合、ロックに使用されているオブジェクト(同期後の同期ブラケットの内容)を明確に確認する必要があります。同じオブジェクトで同期されたスレッドは互いにブロックされ、異なるオブジェクトにロックされているスレッドは互いにブロックされません。
5。同期する必要があるのはいつですか
複数のスレッドが相互に排他的に(交換可能な)データに同時にアクセスする場合、データを保護するために同期して、両方のスレッドが同時に変更されて変更されないようにする必要があります。
非静的フィールドで変更できるデータの場合、通常、非静的な方法にアクセスします。
静的フィールドで変更できるデータの場合、通常、静的メソッドを使用してアクセスされます。
非静的な方法で静的フィールドを使用するか、静的フィールドで非静的な方法を呼び出す必要がある場合、問題は非常に複雑になります。 SJCP試験の範囲を超えています。
6。スレッド安全カテゴリ
クラスがデータを保護するためによく同期されている場合、このクラスは「スレッドセーフ」と呼ばれます。
スレッドセーフクラスであっても、動作するスレッドは必ずしも安全ではないため、非常に注意する必要があります。
7。スレッド同期の概要
1.スレッドの同期の目的は、複数のスレッドがリソースにアクセスしたときにリソースの損傷を保護することです。
2。スレッド同期メソッドは、ロックを介して実装されます。各オブジェクトには1つのロックのみがあります。このロックは特定のオブジェクトに関連付けられています。スレッドがオブジェクトロックを取得すると、オブジェクトにアクセスする他のスレッドは、オブジェクトの他の同期メソッドにアクセスできなくなります。
3。静的同期方法の場合、ロックはこのクラス用であり、ロックオブジェクトはこのクラスのクラスオブジェクトです。静的および非静的な方法のロックは互いに干渉しません。スレッドがロックを取得し、同期方法で別のオブジェクトに同期方法にアクセスすると、これら2つのオブジェクトロックを取得します。
4。同期するには、どのオブジェクトが同期するかを常に認識することが鍵です。
5.スレッドセーフクラスを作成する場合、リソースにアクセスするために競合する複数のスレッドのロジックとセキュリティに関する正しい判断を下し、「原子」操作を分析し、他のスレッドが原子動作中に競合するリソースにアクセスできないことを常に注意する必要があります。
6.複数のスレッドがオブジェクトロックを待っている場合、ロックを取得していないスレッドがブロックされます。
7.デッドロックは、お互いがロックするのを待っているスレッドが原因であり、実際に発生する可能性は非常に少ないです。デッドロックプログラムを本当に書きたいなら、使いやすいことではないかもしれません。ただし、プログラムが死ぬと、プログラムは死にます。
オリジナルリンク:http://www.cnblogs.com/linjiqin/p/3208843.html
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。