【Java】wait notify 爲什麼放在同步塊內

wait、notify和notifyAll三個方法必須放在同步塊內執行。

現象:

如果不放在同步塊內,運行時會拋出這個異常:
IllegalMonitorStateException。

原因:

因爲wait和notify(包括notifyAll,爲了方便,後面僅寫notify)的使用一般而言,都是成對的(自己等待,通知別人)。

舉一個生產者消費者的例子,大概是下面這樣的模式:

生產者producer:

if full

   wait;

else 

  produce;

  notify consumer;

消費者consumer:

if empty

  wait

else  

  do consume;

  notify producer;

如果消費者或者生產者的邏輯不放在同步塊內,那麼整個生產或者消費就不是原子性的操作,那麼可能會有這樣的問題:

比如說生產者先判斷full,那麼準備執行wait,但是此時線程切換到了消費者,消費者執行消費,並且notify。隨後又切換到了生產者線程,此時由於消費者消費了,那麼就不是full了,生產者本應該生產,但是卻繼續執行了wait,等於說之前的一次notify丟失了。

回顧一下這個過程,本質上是因爲wait和notify的操作不是同步執行導致的。所以,wait和notify執行前必須拿到鎖才行,這就是需要放到同步塊內執行的原因。

最後,打開wait方法的源碼:

     * <pre>
     *     synchronized (obj) {
     *         while (&lt;condition does not hold&gt;)
     *             obj.wait();
     *         ... // Perform action appropriate to condition
     *     }
     * </pre>

作者建議wait的調用應該始終用如上形式:

1.同步;

2.while判斷條件,而不是if;

同步的原因上面已經解釋過了。爲什麼要用while?

這是因爲,如果線程數不止一個,比如消費者和生產者都有多個線程,那麼notify後,只有一個線程可以執行,其餘的線程仍然需要wait,此時就必須用while保證可以重新while。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章