Java并發(fā)編程中的等待/喚醒機(jī)制與鎖對(duì)象
在Java并發(fā)編程中,正確運(yùn)用wait()和notifyAll()方法至關(guān)重要。本文闡述了為什么在使用這些方法時(shí),鎖對(duì)象不應(yīng)是業(yè)務(wù)數(shù)據(jù)對(duì)象,例如文中提到的食物數(shù)量food。
文中以廚師做菜、食客吃菜的例子說(shuō)明了這個(gè)問(wèn)題。直觀(guān)上,food似乎是合適的鎖對(duì)象,因?yàn)閺N師和食客的操作都圍繞著它進(jìn)行。然而,示例代碼表明,直接使用food作為synchronized參數(shù)會(huì)導(dǎo)致程序錯(cuò)誤,必須引入獨(dú)立的Object對(duì)象lock作為鎖。
這是因?yàn)閟ynchronized關(guān)鍵字的鎖作用于對(duì)象本身,而非對(duì)象的值。food是Integer類(lèi)型的變量,它本身是對(duì)象,但存儲(chǔ)的是數(shù)值,而非同步鎖。如果使用food作為鎖,food值改變時(shí),鎖對(duì)象也隨之改變,引發(fā)嚴(yán)重的并發(fā)問(wèn)題。
立即學(xué)習(xí)“Java免費(fèi)學(xué)習(xí)筆記(深入)”;
分析如下場(chǎng)景:假設(shè)food為0,消費(fèi)者線(xiàn)程阻塞。生產(chǎn)者線(xiàn)程將food設(shè)為1時(shí),消費(fèi)者線(xiàn)程仍持有food值為0時(shí)的鎖,該鎖未釋放,導(dǎo)致消費(fèi)者線(xiàn)程持續(xù)等待,程序無(wú)法正常工作。
因此,需要一個(gè)獨(dú)立的鎖對(duì)象,與業(yè)務(wù)數(shù)據(jù)無(wú)關(guān),只負(fù)責(zé)線(xiàn)程同步。該鎖對(duì)象可以是簡(jiǎn)單的Object實(shí)例或?qū)iT(mén)設(shè)計(jì)的鎖類(lèi)。它在整個(gè)過(guò)程中保持不變,確保所有線(xiàn)程操作的是同一個(gè)鎖對(duì)象。 Integer對(duì)象的緩存機(jī)制也可能導(dǎo)致直接使用Integer變量作為鎖出現(xiàn)潛在問(wèn)題,因此使用新的Object對(duì)象作為鎖是最安全可靠的做法。 文中Desk.lock就起到了這個(gè)作用,它是一個(gè)獨(dú)立的Object對(duì)象,僅用于同步,與食物數(shù)量food完全隔離,保證了程序的正確性。