Javaのスレッドの排他制御のサンプルです。synchronizedを使用します。
目次
サンプル | メソッドにsynchronizedを指定 |
ブロックにsynchronizedを指定 |
メソッドにsynchronizedを指定
2つのスレッドが、1つのインスタンスの変数にほぼ同じタイミングでアクセスします。
このコードではsynchronizedで排他制御をかけていない場合以下の挙動になります。
想定:1つめのスレッドが変数の値の10に1を追加して11にして出力し、2つめのスレッドが同じ変数の値の11に1を追加し12にして出力する。
実際:それぞれのスレッドが同じ11を出力するときがある。
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); // 同じインスタンスが引数
new Thread(player1).start();
new Thread(player2).start();
}
}
class Counter {
public int count = 10;
// public synchronized int plusOne() {
public int plusOne() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.count = this.count + 1;
return this.count;
}
}
class Player implements Runnable {
private Counter counter;
public Player(Counter counter) {
this.counter = counter;
}
@Override
public void run() {
int num = this.counter.plusOne();
System.out.println(Thread.currentThread().getName()
+ "は" + num + "件です");
}
}
6,7行目のコンストラクタの引数は同じインスタンスです。
8,9行目は、それぞれスレッドが動きます。
21行目は、変数のcountに1を追加します。
実行するとまれに両方のスレッドの結果が11になります。
排他制御を行うためメソッドの前にsynchronizedを指定します。
15行目をコメントにして14行目のコメントを外すと実行結果は当初の想定どうりになります。
ブロックにsynchronizedを指定
上記コードではメソッドの前にsynchronizedを指定しましたが、代わりにsynchronizedとブロックでも排他制御をかけることができます。
class Counter {
public int count = 10;
// public synchronized int plusOne() {
public int plusOne() {
synchronized (this) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.count = this.count + 1;
return this.count;
}
}
}
5~13行目が1つのブロックです。
関連の記事