本篇內(nèi)容介紹了“java的wait/notify/notifyAll方法怎么正確使用”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

韓城網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián)公司,韓城網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為韓城近1000家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)網(wǎng)站建設(shè)要多少錢,請(qǐng)找那個(gè)售后服務(wù)好的韓城做網(wǎng)站的公司定做!
源碼中對(duì)wait方法的介紹如下:
/**
* As in the one argument version, interrupts and spurious wakeups are
* possible, and this method should always be used in a loop:
* <pre>
* synchronized (obj) {
* while (<condition does not hold>)
* obj.wait();
* ... // Perform action appropriate to condition
* }
* </pre>
* This method should only be called by a thread that is the owner
* of this object's monitor. See the {@code notify} method for a
* description of the ways in which a thread can become the owner of
* a monitor.
*
*/
public final void wait() throws InterruptedException {
wait(0);
}意思是說(shuō),在使用 wait 方法時(shí),必須把 wait 方法寫(xiě)在 synchronized 保護(hù)的 while 代碼塊中,并始終判斷執(zhí)行條件是否滿足,如果滿足就往下繼續(xù)執(zhí)行,如果不滿足就執(zhí)行 wait 方法,而在執(zhí)行 wait 方法之前,必須先持有對(duì)象的 monitor 鎖,也就是通常所說(shuō)的 synchronized 鎖。
class BlockingQueue{
Queue<String> buffer = new LinkedList<>();
public void give(String data){
buffer.add(data);
notify();
}
public String take() throws InterruptedException {
while(buffer.isEmpty()){
wait();
}
return buffer.remove();
}
}在代碼中可以看到有兩個(gè)方法,give 方法負(fù)責(zé)往 buffer 中添加數(shù)據(jù),添加完之后執(zhí)行 notify 方法來(lái)喚醒之前等待的線程,而 take 方法負(fù)責(zé)檢查整個(gè) buffer 是否為空,如果為空就進(jìn)入等待,如果不為空就取出一個(gè)數(shù)據(jù),這是典型的生產(chǎn)者消費(fèi)者的思想。
在如上所示的代碼中沒(méi)有正確使用wait()方法,那么可能出現(xiàn)什么異常呢?
首先,消費(fèi)者線程調(diào)用 take 方法并判斷 buffer.isEmpty 方法是否返回 true,若為 true 代表buffer是空的,則線程希望進(jìn)入等待,但是在線程調(diào)用 wait 方法之前(while(buffer.isEmpty())之后),就被調(diào)度器暫停了,所以此時(shí)還沒(méi)來(lái)得及執(zhí)行 wait 方法。
此時(shí)生產(chǎn)者開(kāi)始運(yùn)行,執(zhí)行了整個(gè) give 方法,它往 buffer 中添加了數(shù)據(jù),并執(zhí)行了 notify 方法,但 notify 并沒(méi)有任何效果,因?yàn)?strong>消費(fèi)者線程的 wait 方法沒(méi)來(lái)得及執(zhí)行,所以沒(méi)有線程在等待被喚醒。
此時(shí),剛才被調(diào)度器暫停的消費(fèi)者線程回來(lái)繼續(xù)執(zhí)行 wait 方法并進(jìn)入了等待,這時(shí)消費(fèi)者便有可能陷入無(wú)窮無(wú)盡的等待,因?yàn)樗e(cuò)過(guò)了剛才 give 方法內(nèi)的 notify 的喚醒。
ps:上面說(shuō)的調(diào)度器暫停線程,因?yàn)樵诙嗑€程下,CPU 的調(diào)度是以時(shí)間片為單位進(jìn)行分配的,每個(gè)線程都可以得到一定量的時(shí)間片。但如果線程擁有的時(shí)間片耗盡,它將會(huì)被暫停執(zhí)行并讓出 CPU 資源給其他線程。而代碼中的“判斷-執(zhí)行”不是一個(gè)原子操作,它在中間有可能被打斷,是線程不安全的,所以說(shuō)有可能在線程調(diào)用 wait 方法之前這個(gè)線程就被暫停了。
class BlockingQueue{
Queue<String> buffer = new LinkedList<>();
public void give(String data){
synchronized (this){
buffer.add(data);
notify();
}
}
public String take() throws InterruptedException {
synchronized (this){
while(buffer.isEmpty()){
wait();
}
return buffer.remove();
}
}
}這樣就可以確保 notify 方法永遠(yuǎn)不會(huì)在 buffer.isEmpty 和 wait 方法之間被調(diào)用,提升了程序的安全性。另外,wait 方法會(huì)釋放 monitor 鎖,這也要求我們必須首先進(jìn)入到 synchronized 內(nèi)持有這把鎖。
線程可能在既沒(méi)有被notify/notifyAll,也沒(méi)有被中斷或者超時(shí)的情況下被喚醒,這種喚醒是我們不希望看到的。然在實(shí)際生產(chǎn)中,虛假喚醒發(fā)生的概率很小,但是程序依然需要保證在發(fā)生虛假喚醒的時(shí)候的正確性,所以就需要采用while循環(huán)的結(jié)構(gòu)。
while (condition does not hold) obj.wait();
這樣即便被虛假喚醒了,也會(huì)再次檢查while里面的條件,如果不滿足條件,就會(huì)繼續(xù)wait,也就消除了虛假喚醒的風(fēng)險(xiǎn)。
它們都可以讓線程阻塞
它們都可以響應(yīng) interrupt 中斷:在等待的過(guò)程中如果收到中斷信號(hào),都可以進(jìn)行響應(yīng),并拋出 InterruptedException 異常。
wait 方法必須在 synchronized 保護(hù)的代碼中使用,而 sleep 方法并沒(méi)有這個(gè)要求。
在同步代碼中執(zhí)行 sleep 方法時(shí),并不會(huì)釋放 monitor 鎖,但執(zhí)行 wait 方法時(shí)會(huì)主動(dòng)釋放 monitor 鎖。
sleep 方法中會(huì)要求必須定義一個(gè)時(shí)間,時(shí)間到期后會(huì)主動(dòng)恢復(fù),而對(duì)于沒(méi)有參數(shù)的 wait 方法而言,意味著永久等待,直到被中斷或被喚醒才能恢復(fù),它并不會(huì)主動(dòng)恢復(fù)。
wait/notify/notifyAll 被定義在 Object 類中,而 sleep 定義在 Thread 類中。
首先因?yàn)?Java 中每個(gè)對(duì)象都有一把稱之為 monitor 監(jiān)視器的鎖,每個(gè)對(duì)象都可以上鎖,在對(duì)象頭中有一個(gè)用來(lái)保存鎖信息的位置。這個(gè)鎖是對(duì)象級(jí)別的,而非線程級(jí)別的,wait/notify/notifyAll 也都是鎖級(jí)別的操作,它們的鎖屬于對(duì)象,所以把它們定義在 Object 類中是最合適,因?yàn)?Object 類是所有對(duì)象的父類。
其次,一個(gè)線程可能持有多把鎖,以便實(shí)現(xiàn)相互配合的復(fù)雜邏輯,既然我們是讓當(dāng)前線程去等待某個(gè)對(duì)象的鎖,自然應(yīng)該通過(guò)操作對(duì)象來(lái)實(shí)現(xiàn),而不是操作線程。
“java的wait/notify/notifyAll方法怎么正確使用”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
標(biāo)題名稱:java的wait/notify/notifyAll方法怎么正確使用
網(wǎng)頁(yè)路徑:http://chinadenli.net/article14/ipcode.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站設(shè)計(jì)、虛擬主機(jī)、靜態(tài)網(wǎng)站、移動(dòng)網(wǎng)站建設(shè)、響應(yīng)式網(wǎng)站、品牌網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)