Java スレッドの排他制御(synchronized/join)

Javaのスレッドの排他制御のサンプルです。synchronizedまたはjoinを使用します。

目次

サンプル メソッドにsynchronizedを指定
  ブロックにsynchronizedを指定
  joinメソッドを使用

メソッドにsynchronizedを指定

2つのスレッドが、1つのインスタンスの変数に対してアクセスするサンプルです。

package test1;

public class Test1 {
	public static void main(String[] args) {
		Counter Counter = new Counter();
		Player player1 = new Player(Counter); // 同じインスタンスが引数
		Player player2 = new Player(Counter); // 同じインスタンスが引数
		player1.start();
		player2.start();
	}
}

class Counter {
	public int count = 10;

	// public synchronized int plusOne(int num) {
	public int plusOne(int num) {

		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.count = this.count + num;
		return this.count;
	}
}

class Player extends Thread {
	private Counter counter;

	public Player(Counter counter) {
		this.counter = counter;
	}

	@Override
	public void run() {
		int num1 = this.counter.plusOne(1);
		String threadName = Thread.currentThread().getName();
		System.out.println(threadName + "の件数は" + num1);
	}
}

5行目は、13行目のクラスのインスタンスを生成しています。
6,7行目は、同じインスタンスを引数としてインスタンス化しています。
8,9行目は、それぞれスレッドが動きます。

38行目は、1を引数にして24行目で10に1を追加します。

想定では、8行目のスレッド(または9行目のスレッド)が1を追加して40行目で11が表示され
9行目のスレッド(または8行目のスレッド)が11に対して1を追加して40行目で12を表示ですが

実際は、以下のように両方とも11の状態がまれに発生します。

 

17行目をコメントにして16行目のコメントを外しsynchronizedを使用すると当初の想定どうりになります。

ブロックにsynchronizedを指定

ブロックにsynchronizedを指定するサンプルです。

class Counter {
	public int count = 10;

	public int plusOne(int num) {

		synchronized (this) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			this.count = this.count + num;
			return this.count;
		}
	}
}

6行目は、ブロックにsynchronizedを指定しています。

joinメソッドを使用

public final void join() throws InterruptedException

synchronizedの代わりにjoinでも制御できます。
joinメソッドは、スレッドが終了するのを待機します。

public class Test1 {
	public static void main(String[] args) {
		Counter Counter = new Counter();
		Player player1 = new Player(Counter); // 同じインスタンスが引数
		Player player2 = new Player(Counter); // 同じインスタンスが引数
		player1.start();
		try {
			player1.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		player2.start();
	}
}

8行目はjoinメソッドです。player1のスレッドが終了してから12行目が実行されます。

https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Thread.html#join--

関連の記事

Java マルチスレッドのサンプル(ThreadとRunnable)

△上に戻る