在多線程的狀況下,因爲同一進程的多個線程共享同一片存儲空間,在帶來方便的同時,也帶來了訪問衝突這個嚴重的問題。Java語言提供了專門機制以解決這種衝突,有效避免了同一個數據對象被多個線程同時訪問。java
wait與notify是java同步機制中重要的組成部分。結合與synchronized關鍵字使用,能夠創建不少優秀的同步模型。
synchronized(this){ }等價於publicsynchronized void method(){.....}
同步分爲類級別和對象級別,分別對應着類鎖和對象鎖。類鎖是每一個類只有一個,若是static的方法被synchronized關鍵字修飾,則在這個方法被執行前必須得到類鎖;對象鎖類同。
首先,調用一個Object的wait與notify/notifyAll的時候,必須保證調用代碼對該Object是同步的,也就是說必須在做用等同於synchronized(obj){......}的內部纔可以去調用obj的wait與notify/notifyAll三個方法,不然就會報錯:
java.lang.IllegalMonitorStateException:current thread not owner
在調用wait的時候,線程自動釋放其佔有的對象鎖,同時不會去申請對象鎖。當線程被喚醒的時候,它纔再次得到了去得到對象鎖的權利。
因此,notify與notifyAll沒有太多的區別,只是notify僅喚醒一個線程並容許它去得到鎖,notifyAll是喚醒全部等待這個對象的線程並容許它們去得到對象鎖,只要是在synchronied塊中的代碼,沒有對象鎖是步履維艱的。其實喚醒一個線程就是從新容許這個線程去得到對象鎖並向下運行。多線程
notifyAll,雖然是對每一個wait的對象都調用一次notify,可是這個仍是有順序的,每一個對象都保存這一個等待對象鏈,調用的順序就是這個鏈的順序。其實啓動等待對象鏈中各個線程的也是一個線程,在具體應用的時候,須要注意一下。oracle
wait(),notify(),notifyAll()不屬於Thread類,而是屬於Object基礎類,也就是說每一個對像都有wait(),notify(),notifyAll()的功能。由於都個對像都有鎖,鎖是每一個對像的基礎,固然操做鎖的方法也是最基礎了。this
wait():spa
等待對象的同步鎖,須要得到該對象的同步鎖才能夠調用這個方法,不然編譯能夠經過,但運行時會收到一個異常:IllegalMonitorStateException。.net
調用任意對象的 wait() 方法致使該線程阻塞,該線程不可繼續執行,而且該對象上的鎖被釋放。線程
notify():對象
喚醒在等待該對象同步鎖的線程(只喚醒一個,若是有多個在等待),注意的是在調用此方法的時候,並不能確切的喚醒某一個等待狀態的線程,而是由JVM肯定喚醒哪一個線程,並且不是按優先級。blog
調用任意對象的notify()方法則致使因調用該對象的 wait()方法而阻塞的線程中隨機選擇的一個解除阻塞(但要等到得到鎖後才真正可執行)。進程
notifyAll():
喚醒全部等待的線程,注意喚醒的是notify以前wait的線程,對於notify以後的wait線程是沒有效果的。
一般,多線程之間須要協調工做:若是條件不知足,則等待;當條件知足時,等待該條件的線程將被喚醒。在Java中,這個機制的實現依賴於wait/notify。等待機制與鎖機制是密切關聯的。
例如:
synchronized(obj) {
while(!condition) {
obj.wait();
}
obj.doSomething();
}
當線程A得到了obj鎖後,發現條件condition不知足,沒法繼續下一處理,因而線程A就wait()。
在另外一線程B中,若是B更改了某些條件,使得線程A的condition條件知足了,就能夠喚醒線程A :
synchronized(obj) {
condition = true;
obj.notify();
}
須要注意的概念是:
# 調用obj的wait(), notify()方法前,必須得到obj鎖,也就是必須寫在synchronized(obj){...} 代碼段內。
# 調用obj.wait()後,線程A就釋放了obj的鎖,不然線程B沒法得到obj鎖,也就沒法在synchronized(obj){...} 代碼段內喚醒A。
# 當obj.wait()方法返回後,線程A須要再次得到obj鎖,才能繼續執行。
#若是A1,A2,A3都在obj.wait(),則B調用obj.notify()只能喚醒A1,A2,A3中的一個(具體哪個由JVM決定)。
#obj.notifyAll()則能所有喚醒A1,A2,A3,可是要繼續執行obj.wait()的下一條語句,必須得到obj鎖,所以,A1,A2,A3只有一個有機會得到鎖繼續執行,例如A1,其他的須要等待A1釋放obj鎖以後才能繼續執行。
# 當B調用obj.notify/notifyAll的時候,B正持有obj鎖,所以,A1,A2,A3雖被喚醒,可是仍沒法得到obj鎖。直到B退出synchronized塊,釋放obj鎖後,A1,A2,A3中的一個纔有機會得到鎖繼續執行。
談一下synchronized和wait()、notify()等的關係:
1.有synchronized的地方不必定有wait,notify
2.有wait,notify的地方必有synchronized.這是由於wait和notify不是屬於線程類,而是每個對象都具備的方法,並且,這兩個方法都和對象鎖有關,有鎖的地方,必有synchronized。
另外,注意一點:若是要把notify和wait方法放在一塊兒用的話,必須先調用notify後調用wait,由於若是調用完wait,該線程就已經不是currentthread了。
本文轉自http://blog.csdn.net/oracle_microsoft/article/details/6863662