某天我在***的時候,突然有個小夥伴微信上說:“哥,阿裏面試又又挂了,被問到爲什麽wait()方法要放在同步塊中,沒答出來!”
但是,爲毛呢??我也沒去了解過。
機智如我立刻假裝正在開會忙得不可開交,回了一條:“開會中,等會和你細說。”
這就是所謂的lost wake up問題。
那麽怎麽解決這個問題呢?
現在我們應該就能夠看到,問題的根源在于,消費者在檢查count到調用wait()之間,count就可能被改掉了。
這就是一種很常見的競態條件。
很自然的想法是,讓消費者和生産者競爭一把鎖,競爭到了的,才能夠修改count的值。
于是生産者的代碼是:
tryLock() count+1 notify() releaseLock()
消費者的代碼是:
tryLock() while(count <= 0) wait() count-1 releaseLock
注意的是,我這裏將兩者的兩個操作都放進去了同步塊中。
現在來思考一個問題,生産者代碼這樣修改行不行?
tryLock() count+1 notify() releaseLock()
答案是,這樣改毫無卵用,依舊會出現lost wake up問題,而且和無鎖的表現是一樣的。
終極答案
所以,我們可以總結到,爲了避免出現這種lost wake up問題,在這種模型之下,總應該將我們的代碼放進去的同步塊中。
Java強制我們的wait()/notify()調用必須要在一個同步塊中,就是不想讓我們在不經意間出現這種lost wake up問題。
不僅僅是這兩個方法,包括java.util.concurrent.locks.Condition的await()/signal()也必須要在同步塊中:
private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); @Test public void test() { try { condition.signal(); } catch (Exception e) { e.printStackTrace(); } }

