在java多線程中可以使用object.wait/notify來(lái)進(jìn)行線程之間的通訊 wait會(huì)使當(dāng)前線程進(jìn)入等待狀態(tài),notify會(huì)從等待線程中隨機(jī)解除其等待狀態(tài)
注意:
- 使用wait 必須進(jìn)行try catch
- 記住調(diào)用wait或者notify方法必須采用當(dāng)前鎖調(diào)用,即必須采用synchronized中的對(duì)象歌懒,wait的本意是暫時(shí)釋放掉對(duì)象鎖嚼吞,讓別的需要此對(duì)象的代碼能夠有機(jī)會(huì)執(zhí)行。
舉個(gè)例子
當(dāng)線程B訪問(wèn)某個(gè)共享資源時(shí),想獲取資源的鎖對(duì)象狂男,發(fā)現(xiàn)這個(gè)鎖已經(jīng)被線程A拿到了埠忘,這個(gè)時(shí)候脾拆,線程B只能被掛起,等待線程A釋放鎖莹妒。
但是拿到鎖的線程A在執(zhí)行的過(guò)程中假丧,因?yàn)槟承l件還不滿足,暫時(shí)不想繼續(xù)執(zhí)行下去动羽,想先等待一下(注意:是已經(jīng)拿到鎖的線程A自己想主動(dòng)等待的)包帚,希望等到某個(gè)條件滿足后,繼續(xù)執(zhí)行任務(wù)运吓。在同步代碼塊里渴邦,線程A必須先釋放鎖,線程B才有資格獲取鎖拘哨,進(jìn)入同步代碼塊谋梭,執(zhí)行代碼。等線程B執(zhí)行完后倦青,線程A需要的條件已經(jīng)滿足瓮床,那么這個(gè)時(shí)候必須有一個(gè)通知機(jī)制,讓線程A從等待狀態(tài)變成執(zhí)行狀態(tài),繼續(xù)執(zhí)行代碼隘庄。
所以線程之間要協(xié)調(diào)溝通踢步,必須有一個(gè)等待機(jī)制和通知機(jī)制,在JAVA里面丑掺,對(duì)應(yīng)的就是wait方法和notify方法获印。
Object的wait方法
synchronized (obj) {
while (condition does not ok){
obj.wait();
}
}
如果想讓線程A處于等待狀態(tài),可以調(diào)用當(dāng)前對(duì)象wait方法街州。wait方法一旦被調(diào)用兼丰,也就意味著:線程A已經(jīng)獲得鎖了,而且能做的事情都已經(jīng)做了唆缴,現(xiàn)在只能等待了鳍征,等待另外的同步操作執(zhí)行某些代碼后,我才回來(lái)繼續(xù)干活面徽。
注意:
永遠(yuǎn)不要在循環(huán)之外調(diào)用wait方法
對(duì)于從wait中被notify的進(jìn)程來(lái)說(shuō)蟆技,它在被notify之后還需要重新檢查是否符合執(zhí)行條件,如果不符合斗忌,就必須再次被wait质礼,如果符合才能往下執(zhí)行。所以:wait方法應(yīng)該使用循環(huán)模式來(lái)調(diào)用织阳。按照上面的生產(chǎn)者和消費(fèi)者問(wèn)題來(lái)說(shuō):錯(cuò)誤情況一:如果有兩個(gè)生產(chǎn)者A和B眶蕉,一個(gè)消費(fèi)者C。當(dāng)存儲(chǔ)空間滿了之后唧躲,生產(chǎn)者A和B都被wait造挽,進(jìn)入等待喚醒隊(duì)列。當(dāng)消費(fèi)者C取走了一個(gè)數(shù)據(jù)后弄痹,如果調(diào)用了notifyAll()饭入,注意,此處是調(diào)用notifyAll()肛真,則生產(chǎn)者線程A和B都將被喚醒谐丢,如果此時(shí)A和B中的wait不在while循環(huán)中而是在if中,則A和B就不會(huì)再次判斷是否符合執(zhí)行條件蚓让,都將直接執(zhí)行wait()之后的程序乾忱,那么如果A放入了一個(gè)數(shù)據(jù)至存儲(chǔ)空間,則此時(shí)存儲(chǔ)空間已經(jīng)滿了历极;但是B還是會(huì)繼續(xù)往存儲(chǔ)空間里放數(shù)據(jù)窄瘟,錯(cuò)誤便產(chǎn)生了。錯(cuò)誤情況二:如果有兩個(gè)生產(chǎn)者A和B趟卸,一個(gè)消費(fèi)者C蹄葱。當(dāng)存儲(chǔ)空間滿了之后氏义,生產(chǎn)者A和B都被wait,進(jìn)入等待喚醒隊(duì)列图云。當(dāng)消費(fèi)者C取走了一個(gè)數(shù)據(jù)后惯悠,如果調(diào)用了notify(),則A和B中的一個(gè)將被喚醒琼稻,假設(shè)A被喚醒,則A向存儲(chǔ)空間放入了一個(gè)數(shù)據(jù)饶囚,至此空間就滿了帕翻。A執(zhí)行了notify()之后,如果喚醒了B萝风,那么B不會(huì)再次判斷是否符合執(zhí)行條件嘀掸,將直接執(zhí)行wait()之后的程序,這樣就導(dǎo)致向已經(jīng)滿了數(shù)據(jù)存儲(chǔ)區(qū)中再次放入數(shù)據(jù)规惰。錯(cuò)誤產(chǎn)生睬塌。