今回はsynchronizedメソッドの話。「synchronizedが付いているメソッドは同時に実行されない」と思っていたら大まちがい。
下記に4種類のコード例のうち、System.out.println()が排他的に実行されるのは2つだけ。
System.outする箇所にブレークポイントを設定してデバッグすると動作がよく分かる。
SynchronizedTest.java
public class SynchronizedTest { public static void main(String[] args) { SomeThread someThread = new SomeThread(); Thread t1 = new Thread(someThread); t1.setName("Thread-1"); Thread t2 = new Thread(someThread); t2.setName("Thread-2"); t1.start(); t2.start(); } } class SomeThread implements Runnable { public void run() { for (int i = 0; i < 100; i++) { // これは意図したとおり排他的に動く // mainの中でThreadをnewする時、同じSomeThreadのインスタンスを使っているので、 // 同じロックでガードされる synchronizedMethod(i); } } private synchronized void synchronizedMethod(int i) { System.out.println(Thread.currentThread().getName() + " : " + i); } }
SynchronizedTest2.java
public class SynchronizedTest2 { public static void main(String[] args) { SomeThread2 someThread = new SomeThread2(); Thread t1 = new Thread(someThread); t1.setName("Thread-1"); Thread t2 = new Thread(someThread); t2.setName("Thread-2"); t1.start(); t2.start(); } } class SomeThread2 implements Runnable { public void run() { for (int i = 0; i < 100; i++) { // これは意図したとおり排他的に動かない // synchronizedMethod(i)はsynchronizedだが、SynchronizedMethodClassのインスタンスが // 異なる(毎回newしている)ので、ロックでガードされない new SynchronizedMethodClass().synchronizedMethod(i); } } } class SynchronizedMethodClass { synchronized void synchronizedMethod(int i) { System.out.println(Thread.currentThread().getName() + " : " + i); } }
SynchronizedTest3.java
public class SynchronizedTest3 { public static void main(String[] args) { SomeThread3 someThread = new SomeThread3(); Thread t1 = new Thread(someThread); t1.setName("Thread-1"); Thread t2 = new Thread(someThread); t2.setName("Thread-2"); t1.start(); t2.start(); } } class SomeThread3 implements Runnable { SynchronizedMethodClass3 smc = new SynchronizedMethodClass3(); public void run() { for (int i = 0; i < 100; i++) { // これは意図したとおり排他的に動く // mainの中でThreadをnewする時、同じSomeThread3のインスタンスを使っているので、 // 同じロックでガードされる smc.synchronizedMethod(i); } } } class SynchronizedMethodClass3 { synchronized void synchronizedMethod(int i) { System.out.println(Thread.currentThread().getName() + " : " + i); } }
SynchronizedTest4.java
public class SynchronizedTest4 { public static void main(String[] args) { SomeThread4 someThread = new SomeThread4(); SomeThread4 someThread2 = new SomeThread4(); Thread t1 = new Thread(someThread); t1.setName("Thread-1"); Thread t2 = new Thread(someThread2); t2.setName("Thread-2"); t1.start(); t2.start(); } } class SomeThread4 implements Runnable { SynchronizedMethodClass4 smc = new SynchronizedMethodClass4(); public void run() { for (int i = 0; i < 100; i++) { // これは意図したとおり排他的に動かない // mainの中でThreadをnewする時、違うSomeThread4のインスタンスを使っているので、 // 同じロックでガードされない smc.synchronizedMethod(i); } } } class SynchronizedMethodClass4 { synchronized void synchronizedMethod(int i) { System.out.println(Thread.currentThread().getName() + " : " + i); } }