前言
wait和notify必須在synchronized塊中,否則會拋出IllegalMonitorStateException。
原因
代碼示例
class BlockingQueue {
Queue<String> buffer = new LinkedList<String>();
public void give(String data) {
buffer.add(data);
notify();
}
public String take() throws InterruptedException {
while (buffer.isEmpty())
wait();
return buffer.remove();
}
}
代碼示例的問題所在
一個消費者調用take,發現buffer.isEmpty。
在消費者調用wait之前,由於cpu的調度,消費者線程被掛起,生產者調用give,然后notify。
然后消費者調用wait (注意,由於錯誤的條件判斷,導致wait調用在notify之后,這是關鍵)。
如果很不幸的話,生產者產生了一條消息后就不再生產消息了,那么消費者就會一直掛起,無法消費,造成死鎖。
關鍵
總是讓give/notify和take/wait為原子操作。wait/notify是線程之間的通信,他們存在競態,我們必須保證在滿足條件的情況下才進行wait。換句話說,如果不加鎖的話,那么wait被調用的時候可能wait的條件已經不滿足了(如上述)。由於錯誤的條件下進行了wait,那么就有可能永遠不會被notify到,所以我們需要強制wait/notify在synchronized中。