synchronized文

javaでは複数のスレッドが同時並列的に動くプログラムは簡単に書けます。同時に複数のスレッドで処理したいが、ただランダムにアクセスされては困るような場合があります。典型的な例が書き込み用ファイルや、そのファイルのためにメモリ上に展開されてるデータのupdate処理をするような場合です。
複数のスレッドがランダムに処理をしていたら内容がめちゃめちゃになるのでなんとか制御したい!というようなときに、このsynchronizedという修飾子を使います。

public syschronized void yMethod(){
	・・・
}

特定のオブジェクトに対して複数のスレッドが順序正しくアクセスしたときは、

sysnchronized(myImportantObject){
	・・・      // myImportantObjectを扱うブロック
	・・・
}

synchronizedで修飾されたメソッドやオブジェクトにはそのメソッドや文ブロックに一度に一つのスレッドしかアクセスできません。他のスレッドは今アクセスしているスレッドや文ブロックが処理を終えるまで待つ事になります。待ち行列ができるわけですね。逆に言うとここで変な重い処理を実装してしまうとこの部分で処理が詰まってしまい、それ以降アクセスしにくるスレッドが溜まってしまいOutOfMemoryや、スレッドオーバーなどのエラーを引き起こす要因となってしまいます。

// 5つのスレッドを発生し、共有オブジェクトのデータにアクセス
// それぞれのスレッドは、同じオブジェクトのデータを取得し、1を加える。

// 共有するデータを保持するクラス
class Share{
	private int x = 0;
	
	// 同期指定したメソッド
	public synchronized void addX(){
		int a = x;
		try{
			Thread.sleep(2000);
		}catch(InterruptedException e){
			System.out.println("Share;" + e);
		}
		x = a + 1;
		System.out.println(a);
	}
}

// マルチスレッドで実行するクラス
class Sync implements Runnable{
	Share var;
	
	Sync(Share obj){
		var = obj;
	}
	
	public void run(){
		var.addX();
	}
}

// コントロールクラス
class SyncTest{
	public static void main(String[] args){
		Share obj = new Share();
		System.out.println("count:" + obj.getX());
		
		Thread[] thres = new Thread[5];
		
		for(int i=0;i<5;i++){
			thres[i] = new Thread(new Sync(obj));
			thres[i].start();
		}
		
		for(int i=0;i<5;i++){
			try{
				thres[i].join();
			}catch(InterruptedException e){
				System.out.println("main();" + e);
			}
		}
		
		System.out.println("count:" + obj.getX());
		
	}
}