java.lang.Objectjava
public final native void wait() throws InterruptedException; public final native void wait(long millis, int nanos) throws InterruptedException; public final void wait(long millis) throws InterruptedException { wait(millis, 0); } public final native void notify(); public final native void notifyAll();
wait():使調用該方法的線程釋放鎖,從運行狀態退出,進入等待隊列,直到被喚醒。spa
wait(long timeout):等待一段時間是否有線程喚醒鎖,若是沒有,超時自動喚醒。線程
wait(long timeout, int nanos):等待喚醒時間納秒級別。code
notify():隨機喚醒等待隊列中的等待同一個鎖的一個線程,使這個線程退出等待隊列,進入可運行狀態。對象
notifyAll():喚醒全部等待一樣鎖的全部線程,從等待隊列中退出,進入可運行狀態。隊列
每一個對象都有個monitor,初始是0,執行完synchronized值就是1。ip
wait/notify須要在得到monitor的線程中才能夠執行。資源
因此,wait/notify須要在synchronized中執行。同步
其中,wait又會釋放掉鎖,破壞掉同步。it
synchronized代碼塊生成的字節碼,被monitorenter
和monitorexit
包圍,持有對象的monitor;
線程執行wait/notify方法時,必須持有對象的monitor;
因此,wait/notify方法在synchronized同步塊中執行,就持有了對象的鎖。
Java語言的同步機制在底層實現上只有兩種方式:互斥和協同。
互斥:即synchronized內置鎖。
協同:即內置條件隊列,wait/notify/notifyAll。
條件隊列中是處於等待狀態的線程,等待特定條件爲真。每一個Java對象均可以做爲一個鎖,一樣每一個Java對象均可以做爲一個條件隊列。經過wait/notify/notifyAll來操做條件隊列。
能夠理解爲:有一個隊列,o.wait()就push進去,o.notify()就pull出來。
要調用條件隊列的任何一個方法,都必需要得到對象上的鎖。
線程是用來工做的,不該該處於等待狀態,處於等待狀態的條件隊列中的線程,必定是執行不下去的。
while(condition is not true) { lock.wait() }
解釋:兩個消費者線程c1和c2,邏輯都是,判斷資源是否爲空,是就wait,否就消費一個;某個時刻,兩個線程都進入等待隊列,而後生產者生產了一個資源,並執行notifyAll,喚醒c1和c2都進入鎖池,c1先獲取鎖,執行完消費掉資源,而後釋放鎖,此時,若是c2得到鎖,若是是if邏輯,那麼就會進入消費代碼,可是資源已經被c1消費掉了,可能拋出異常。若是是while邏輯,則不會進入消費代碼,而是繼續等待。
在通常狀況下,總應該調用notifyAll喚醒全部須要被喚醒的線程。可能會喚醒其餘一些線程,但這不影響程序的正確性,這些線程醒來以後,會檢查他們正在等待的條件(循環檢測),若是發現條件不知足,就會繼續等待
顯示鎖:Lock,對應內置鎖synchronized
顯示條件隊列:Condition,對應內置條件隊列,對應方法是await, signal, signalAll