今天的一段代碼拋出了java.lang.IllegalMonitorStateException,代碼如下:
class ThreadC implements Runnable{
Boolean falg;
public ThreadC(Boolean falg) {
this.falg = falg;
}
@Override
public void run() {
synchronized (falg){
for (int i = 1; i <= 1000; i++) {
if(i % 2 == 0 && i % 3 == 0 && i % 5 == 0 && i % 7 ==0){
try {
falg = true;//報錯的地方
System.out.println(i+"睡眠!");
falg.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
falg.notify();
}
}
}
}
上網查了很久,終於找到了答案:
真正的問題在於falg這個變量是一個Boolean
falg = true;
Boolean型變量在執行賦值語句的時候,其實是創建了一個新的對象。簡單的說,在賦值語句的之前和之後,falg並不是同一個對象。
synchronzied(falg)綁定的是舊的Boolean對象,而重新賦值後新的Boolean對象並沒有使用synchronzied進行同步,所以系統拋出了IllegalMonitorStateException異常。
相同的悲劇還有可能出現在falg是Integer或者String類型的時候。
一個解決方案是採用java.util.concurrent.atomic中對應的類型,比如這裏就應該是AtomicBoolean。採用AtomicBoolean類型,可以保證對它的修改不會產生新的對象。
正確的代碼:
class ThreadC implements Runnable{
AtomicBoolean falg;
public ThreadC(AtomicBoolean falg) {
this.falg = falg;
}
@Override
public void run() {
synchronized (falg) {
for (int i = 1; i <= 1000; i++) {
if (i % 2 == 0 && i % 3 == 0 && i % 5 == 0 && i % 7 == 0) {
try {
falg.set(true);
System.out.println(i + "睡眠!");
falg.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
falg.notify();
}
}
}
}