In other words,
* waits should always occur in loops, like this one:
* <pre>
* synchronized (obj) {
* while (<condition does not hold>)
* obj.wait(timeout);
* ... // Perform action appropriate to condition
* }
* </pre>
* (For more information on this topic, see Section 3.2.3 in Doug Lea's
* "Concurrent Programming in Java (Second Edition)" (Addison-Wesley,
* 2000), or Item 50 in Joshua Bloch's "Effective Java Programming
* Language Guide" (Addison-Wesley, 2001).app
synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout);
... // Perform action appropriate to condition
}ide
反證舉例:對象o的wait(notify、notifyAll)若是不在synchronized 同步方法或者 synchronized 同步塊,那麼線程I調用o.wait()時,線程II能夠(同一時間內)隨時調用o.notify(),以下圖函數
線程I處於o.wait()調用後的wait set中,此時代碼運行的指針暫存了起來。oop
由於沒有互斥同步,線程II能夠隨時調用o.notify(),那麼無論線程I中的condition條件是否知足,都會發生【①通知繼續】。ui
隨着【①通知繼續】的發生,線程II認爲:我已經通知過線程I,讓線程I繼續運行了,個人任務完成了!this
線程I中接收到【①通知繼續】,而後會從暫存的位置取出代碼運行指針,繼續往o.wait()後面運行,而後又跑到while(condition)這裏。剛纔說了,condition條件可能還不符合,那麼就又進入了o.wait(),暫存起來運行指針,線程I進入對象o的wait set區。spa
如今是什麼狀況?線程II認爲:我已經通知過線程I,讓線程I繼續運行了,個人任務完成了!因此線程II不會再次通知了。線程
線程I呢?如上所述再次進入了對象o的wait set,由於線程II不會再次notify線程I,那麼線程I將永遠存在於wait set區域,再也出不來了!設計
因此爲啥要同步o.wait()和o.notify()?就是爲了互斥執行,只有condition知足時,才讓線程II通知線程I從wait set區跳出來繼續執行,進而繼續執行後續的代碼。指針
若是wait方法不在while循環中使用,那麼通知wait結束,沒有再次進行條件判斷就繼續wait後續代碼。可是有可能出現condition並不知足的狀況,此時代碼邏輯就亂了。
首先wait方法是屬於類Object。能夠認爲任何一個Object對象都有一個內置鎖,由於Object類是全部類的祖先類,也就是說全部類的對象都有一個內置鎖。想調用wait、notify、notifyAll方法,必需要先獲取對象的內置鎖。
wait被設計時就是要和notify(或者notifyAll)配合使用的。
使用場景就是:對象o,其有一個屬性爲a。屬性a被線程I和線程II共享,也就是說a爲線程I和線程II的共享變量。當a爲true時,線程I調用o的wait。線程II能夠改變o中a的狀態,改變後調用o的notify方法,通知線程I跳出o的wait方法,繼續向後執行代碼。
整體來講,人家設計的就是這個套路。
以前說過。實質上調用代碼1就至關於調用代碼2。分析join的源碼,結合wait的使用套路,能夠獲得這個結論。
假設線程I調用t.join()。t.join()最終調用的是t.wait()。
t.join()方法是synchronized 方法。因此線程I中運行到t.join(),是線程I拿到了對象t的鎖。
將t.join()換成代碼2,也應該以對象t爲鎖。因此代碼2中,仍然是線程I拿到了對象t的鎖。