Java并发编程—notify和notifyAll有什么区别?
原文作者:知乎用戶(hù)
原文地址:https://www.zhihu.com/question/37601861/answer/145545371
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
今天正好碰到這個(gè)問(wèn)題,也疑惑了好久。看了一圈知乎上的答案,感覺(jué)沒(méi)說(shuō)到根上。所以自己又好好Google了一下,終于找到了讓自己信服的解釋。
先說(shuō)兩個(gè)概念:鎖池和等待池
- 鎖池:假設(shè)線(xiàn)程A已經(jīng)擁有了某個(gè)對(duì)象(注意:不是類(lèi))的鎖,而其它的線(xiàn)程想要調(diào)用這個(gè)對(duì)象的某個(gè)synchronized方法(或者synchronized塊),由于這些線(xiàn)程在進(jìn)入對(duì)象的synchronized方法之前必須先獲得該對(duì)象的鎖的擁有權(quán),但是該對(duì)象的鎖目前正被線(xiàn)程A擁有,所以這些線(xiàn)程就進(jìn)入了該對(duì)象的鎖池中(鎖池就是AQS隊(duì)列)。
- 等待池:假設(shè)一個(gè)線(xiàn)程A調(diào)用了某個(gè)對(duì)象的wait()方法,線(xiàn)程A就會(huì)釋放該對(duì)象的鎖后,進(jìn)入到了該對(duì)象的等待池中(等待池就是WaitQueue隊(duì)列))
Reference:
- java中的鎖池和等待池
- Java并發(fā)編程—線(xiàn)程間協(xié)作方式wait()/notify()/notifyAll()原理分析
然后再來(lái)說(shuō)notify和notifyAll的區(qū)別
- 如果線(xiàn)程調(diào)用了對(duì)象的 wait()方法,那么線(xiàn)程便會(huì)處于該對(duì)象的等待池中,等待池中的線(xiàn)程不會(huì)去競(jìng)爭(zhēng)該對(duì)象的鎖。
- 當(dāng)有線(xiàn)程調(diào)用了對(duì)象的 notifyAll()方法(喚醒所有 wait 線(xiàn)程)或 notify()方法(只隨機(jī)喚醒一個(gè) wait 線(xiàn)程),被喚醒的的線(xiàn)程便會(huì)進(jìn)入該對(duì)象的鎖池中,鎖池中的線(xiàn)程會(huì)去競(jìng)爭(zhēng)該對(duì)象鎖。也就是說(shuō),調(diào)用了notify后只要一個(gè)線(xiàn)程會(huì)由等待池進(jìn)入鎖池,而notifyAll會(huì)將該對(duì)象等待池內(nèi)的所有線(xiàn)程移動(dòng)到鎖池中,等待鎖競(jìng)爭(zhēng)
- 優(yōu)先級(jí)高的線(xiàn)程競(jìng)爭(zhēng)到對(duì)象鎖的概率大,假若某線(xiàn)程沒(méi)有競(jìng)爭(zhēng)到該對(duì)象鎖,它還會(huì)留在鎖池中,唯有線(xiàn)程再次調(diào)用 wait()方法,它才會(huì)重新回到等待池中。而競(jìng)爭(zhēng)到對(duì)象鎖的線(xiàn)程則繼續(xù)往下執(zhí)行,直到執(zhí)行完了 synchronized 代碼塊,它會(huì)釋放掉該對(duì)象鎖,這時(shí)鎖池中的線(xiàn)程會(huì)繼續(xù)競(jìng)爭(zhēng)該對(duì)象鎖。
綜上,所謂喚醒線(xiàn)程,另一種解釋可以說(shuō)是將線(xiàn)程由等待池移動(dòng)到鎖池,notifyAll調(diào)用后,會(huì)將全部線(xiàn)程由等待池移到鎖池,然后參與鎖的競(jìng)爭(zhēng),競(jìng)爭(zhēng)成功則繼續(xù)執(zhí)行,如果不成功則留在鎖池等待鎖被釋放后再次參與競(jìng)爭(zhēng)。而notify只會(huì)喚醒一個(gè)線(xiàn)程。有了這些理論基礎(chǔ),后面的notify可能會(huì)導(dǎo)致死鎖,而notifyAll則不會(huì)的例子也就好解釋了。上述過(guò)程的圖示如下:
?
notify方法和notifyAll()方法兩者非常相似,到底該用哪一個(gè),老實(shí)說(shuō),這個(gè)選擇有點(diǎn)困難。選擇notify的話(huà),因?yàn)橐獑拘训木€(xiàn)程比較少(only one),程序的處理速度當(dāng)然比notifyAll略勝一籌。但是選擇notify時(shí),若這部分處理不好,可能會(huì)出現(xiàn)程序掛掉的危險(xiǎn)。一般說(shuō)來(lái),選擇notifyAll所寫(xiě)出來(lái)的程序代碼會(huì)比notify可靠。除非你能確定程序員對(duì)程序代碼的意義和能力限度一清二楚,否則選擇notifyAll應(yīng)該是比較穩(wěn)扎穩(wěn)打。
總結(jié)
以上是生活随笔為你收集整理的Java并发编程—notify和notifyAll有什么区别?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java并发编程—说说Runnable与
- 下一篇: Java并发编程—ThreadLocal