通信的方式
要想實(shí)現(xiàn)多個線程之間的協(xié)同,如:線程執(zhí)行先后順序、獲取某個線程執(zhí)行的結(jié)果等等。涉及到線程之間相互通信,分為下面四類:
- 文件共享
- 網(wǎng)絡(luò)共享
- 共享變量
- jdk提供的線程協(xié)調(diào)API
細(xì)分為:suspend/resume檐嚣、wait/notify、park/unpark
文件共享
變量共享
線程協(xié)作-JDK API
JDK中對于需要多線程協(xié)作完成某一任務(wù)的場景啰扛,提供了對應(yīng)API支持净嘀。
多線程協(xié)作的典型場景:生產(chǎn)者-消費(fèi)者模型(線程阻塞、線程喚醒)
實(shí)例:線程1去賣包子侠讯,沒有包子挖藏,則不再執(zhí)行。線程2生產(chǎn)出包子厢漩,通知線程1繼續(xù)執(zhí)行膜眠。
API-被棄用的suspend和resume
作用:調(diào)用suspend掛起目標(biāo)線程,通過resume可以恢復(fù)線程執(zhí)行溜嗜。
被棄用的主要原因是容易寫出死鎖的代碼宵膨。
所以用wait/notify和park/unpark機(jī)制對它進(jìn)行替代。
suspend和resume死鎖示例
wait/notify機(jī)制
這些方法只能由同一對象鎖的持有者調(diào)用,也就是寫在同步塊里面土全,否則會拋出IllegalMonitorStateException異常捎琐。
wait方法導(dǎo)致當(dāng)前線程等待,加入該對象的等待集合中裹匙,并且放棄當(dāng)前持有的對象鎖瑞凑。notify/notifyAll方法喚醒一個或所有正在等待這個對象的鎖。
注意:雖然wait自動解鎖概页,但是對順序有要求籽御,如果在notify被調(diào)用之后,才開始wait方法的調(diào)用,線程會永遠(yuǎn)處于WAITING狀態(tài)技掏。
park/unpark機(jī)制
線程調(diào)用park則等待“許可”铃将,unpark方法為指定線程提供“許可(permit)”。
不要求park和unpark方法的調(diào)用順序哑梳。
多次調(diào)用unpark之后麸塞,再調(diào)用park,線程會直接運(yùn)行涧衙。
但不會疊加,也就是說奥此,連續(xù)多次調(diào)用park方法弧哎,第一次會拿到“許可”直接運(yùn)行,后續(xù)調(diào)用會進(jìn)入等待稚虎。
偽喚醒
警告撤嫩!之前代碼中用if語句來判斷,是否進(jìn)入等待狀態(tài)蠢终,是錯誤的序攘!
官方建議應(yīng)該在循環(huán)中檢查等待條件,原因是處于等待狀態(tài)的線程可能會收到錯誤警報和偽喚醒寻拂,如果不在循環(huán)中檢查等待條件程奠,程序就會在沒有滿足條件的情況下退出。
偽喚醒是指線程并非因?yàn)閚otify祭钉、notifyall瞄沙、unpark等api調(diào)用而喚醒,是更底層原因?qū)е碌摹?br>