JAvaのsynchronized

3417 ワード

Java tutorial thread synchronizationから 
synchronization(同期)thread interference
スレッド通信は、主にオブジェクトドメインとドメインに関連するオブジェクト参照を共有することによって行われます.この形式の通信は極めて効率的である.しかし、2つのエラーが発生する可能性があります.thread interferenceスレッド干渉とmemory consistency Errorsメモリ整合性エラー.これらのエラーを防止するツールは同期です.
Thread Interfence(スレッド干渉) 
単純なクラスを考える:Counter
class Counter {

	private int c = 0;



	public void increment() {

		c++;

	}



	public void decrement() {

		c--;

	}



	public int value() {

		return c;

	}

}


Counterクラスはincrement呼び出しcごとに1を増加させ、decrement呼び出しcごとに1を減少させる.しかし、1つのCounterオブジェクトが複数のスレッドで参照されると、スレッド間の干渉が私たちが望んでいるように動作するのを妨げる可能性があります.
干渉は、異なるスレッドで実行されるが、同じデータに作用する2つの操作がインタリーブされると発生する.これは、2つの操作が複数のステップを含み、ステップの順序が重複していることを意味する.Counterのオブジェクトに対する操作が漏洩することは不可能である.cに対する2つの操作は単一の簡単な文であるからである.ただし、各単純文は仮想マシンによって複数のステップに翻訳されます.仮想マシンがいくつかのステップに分かれているかを確認しないと、明らかにわかります. 式c++は、次の3つのステップに分割できます.
1.現在のcの値を取り戻す.
2.取り戻したc値を1増加
3.増加したcの値を記憶する
c--同じ方法で分解
スレッドAはincrementメソッドを呼び出し,スレッドBはほぼ同時にdecrementメソッドを呼び出すと仮定する.cの初期値が0の場合、2つのスレッドが交差する動作は、次の順序に従う可能性があります.
1 Thread A: Retrieve c.
2 Thread B: Retrieve c.
3 Thread A: Increment retrieved value; result is 1.
4 Thread B: Decrement retrieved value; result is -1.
5 Thread A: Store result in c; c is now 1.
6 Thread B: Store result in c; c is now -1.
スレッドBに上書きされたため、スレッドAの結果は失われた.この交錯はただ一つの可能性にすぎない.異なる環境では、スレッドBの結果がスレッドAで上書きされているか、エラーが少しもない可能性があります.エラーは予測不可能であるため,スレッド干渉の検出と修正のエラーも異なる.
Memory Consistency Errors
異なるスレッドがデータにアクセスすると、本来のスレッドで得られるデータは同じであるべきだが、異なるものが得られる.メモリ一貫性エラーは複雑です.この問題を回避するための戦略が必要です.
メモリ一貫性エラーを回避する鍵は、発生前の関係を理解することです.この関係は、指定した文に書かれたメモリが別の文に表示されることを保証します.この関係を理解するために,以下の例を考える.int型fieldを定義して初期化するとします.
int counter=0;
スレッドAとBはcounterを共有している field.スレッドAにcounterが追加されたとします.
counter++;
次に、スレッドBはprinterを印刷する:
System.out.println(counter);
上記の2つの文が同じスレッドで実行されている場合、スレッドは安全です.印刷されたcounter値が1であると仮定します.しかし、この2つの文が異なるスレッドで実行される場合、印刷されたcounter値は0になる可能性があります.これは、プログラマがこの2つのスレッドに対して発生前(happens−before)関係を確立していない限り、スレッドAのcounterに対する変更がスレッドBに対して可視であることを保証することはできないからである.
発生前の関係を作成するには、いくつかのアクションがあります.そのうちの1つは、下に示すように同期です.
発生前の関係を作成する2つの動作を見ました.
1つの文がThread.startを呼び出すと、この文と前の関係がある各文、前の関係がある文、新しいスレッドが実行された各文があります.新しいスレッドを作成したコードの効果は、この新しいスレッドに対して表示されます.
あるスレッドが臨界期に達したとき,Thread.join法は別のスレッドに引起され,それから戻る.臨界期に達したスレッドが実行するすべての文と、その後joinが入ってきたすべての文が発生前関係を確立します.このスレッドのコードの効果は、joinが完了したスレッドに対して表示されます.
 
synchronized methods
JAva言語には、同期メソッドと同期文ブロックの2つの基本的な同期構文があります.
メソッドを同期させ、単純にメソッド宣言にsynchronizedキーワードを追加します.

 
   
public class SynchronizedCounter {

	private int c = 0;



	public synchronized void increment() {

		c++;

	}



	public synchronized void decrement() {

		c--;

	}



	public synchronized int value() {

		return c;

	}

}

countがSynchronizedCounterのインスタンスであると すると、2つのメソッドを させると、 のような が られます.
1に、 じオブジェクト の2つの メソッドの び しがインタリーブされることは である.1つのスレッドが1つのオブジェクトの メソッドを している 、このオブジェクトを び す のすべてのスレッドはブロックされます.
このスレッドがこのオブジェクトを したことを っています.
に、 メソッドが すると、 じオブジェクトの メソッドの の び しと に の を します.これにより、このオブジェクトのステータスがすべてのスレッドに されることを します.
されます.
コンストラクタは できません.コンストラクタでsynchronizedキーを するのは エラーで、 コンストラクタは がありません.なぜなら、オブジェクトを している は、オブジェクトを するスレッドしかないからです.
を することができます.