為了支持多線程之間的協(xié)作,JDK提供了兩個非常重要的接口線程等待wait()方法和通知notify()方法解虱。這兩個方法并不是在Thread類中的攘须,而是輸出Object類,這也意味著任何對象都可以調(diào)用這兩個方法殴泰。
那wait()和nofity()是如何工作的呢于宙?如果 一個線程調(diào)用了object.wait(),那么它就會進(jìn)入object對象的等待隊(duì)列悍汛。這個等待隊(duì)列中捞魁,可能會有多個線程,因?yàn)橄到y(tǒng)運(yùn)行多個線程同時等待某一個對象离咐。當(dāng)object.nofity()被調(diào)用時谱俭,它就會從這個等待隊(duì)列中,隨機(jī)選擇一個線程宵蛀,(也不是優(yōu)先通知優(yōu)先級比較高的線程)并將期喚醒昆著。這里希望大家注意的是,這個選擇是不公平的术陶,并不是先等待的線程會優(yōu)先被選擇凑懂,這個選擇完全是隨機(jī)的。
除了nofity()方法外梧宫,Obect對象還有一個類似的notifyAll()方法接谨,它和notify()的功能基本一致,但不同的是塘匣,它會喚醒在這個等待隊(duì)列所有等待的線程疤坝,而不是隨機(jī)選擇一個。這里要注意notifyAll喚醒的是notify之前wait的線程馆铁,對于notify之后的wait線程是沒有效果的跑揉。
這里還需要強(qiáng)調(diào)一點(diǎn),wait()方法并不是可以隨便調(diào)用的埠巨,它必須包含在對應(yīng)的synchronzied語句中历谍,無論是wait()或者notify()都需要首先獲得目標(biāo)對象的一個監(jiān)視器。
當(dāng)需要調(diào)用以上的方法的時候辣垒,一定要對競爭資源進(jìn)行加鎖望侈,如果不加鎖的話,則會報 IllegalMonitorStateException 異常勋桶。
假設(shè)有三個線程執(zhí)行了obj.wait( )脱衙,那么obj.notifyAll( )則能全部喚醒tread1侥猬,thread2,thread3捐韩,但是要繼續(xù)執(zhí)行obj.wait()的下一條語句退唠,必須獲得obj鎖,因此荤胁,tread1瞧预,thread2,thread3只有一個有機(jī)會獲得鎖繼續(xù)執(zhí)行垢油,例如tread1,其余的需要等待thread1釋放obj鎖之后才能繼續(xù)執(zhí)行圆丹。
當(dāng)調(diào)用obj.notify/notifyAll后滩愁,調(diào)用線程依舊持有obj鎖,因此辫封,thread1雅倒,thread2蔑匣,thread3雖被喚醒,但是仍無法獲得obj鎖价脾。直到調(diào)用線程退出synchronized塊,釋放obj鎖后获枝,thread1,thread2懦傍,thread3中的一個才有機(jī)會獲得鎖繼續(xù)執(zhí)行