線程虛假喚醒

一般而言線程調(diào)用wait()方法后,需要其他線程調(diào)用notify,notifyAll方法后,線程才會從wait方法中返回, 而虛假喚醒(spurious wakeup)是指線程通過其他方式,從wait方法中返回。

下面是一個買票退票的操作例子,買票時,線程A買票,如果發(fā)現(xiàn)沒有余票,則會調(diào)用wait方法,線程進(jìn)入等待隊列中,線程B進(jìn)行退票操作,余票數(shù)量加一,然后調(diào)用notify 方法通知等待線程,此時線程A被喚醒執(zhí)行購票操作。

從程序的順序性來看 if (remainTicketNum<=0)沒有問題,但是為什么會出現(xiàn)虛假喚醒呢?

因為wait方法可以分為三個操作:

(1)釋放鎖并阻塞

(2)等待條件cond發(fā)生

(3)獲取通知后,競爭獲取鎖

假設(shè)此時有線程A,C買票,線程A調(diào)用wait方法進(jìn)入等待隊列,線程C買票時發(fā)現(xiàn)線程B在退票,獲取鎖失敗,線程C阻塞,進(jìn)入阻塞隊列,線程B退票時,余票數(shù)量+1(滿足條件2 等待條件發(fā)生),線程B調(diào)用notify方法后,線程C馬上競爭獲取到鎖,購票成功后余票為0,而線程A此時正處于wait方法醒來過程中的第三步(競爭獲取鎖獲取鎖),當(dāng)線程C釋放鎖,線程A獲取鎖后,會執(zhí)行購買的操作,而此時是沒有余票的。

解決的辦法是條件判斷通過while(remainTicketNum<=0)來解決,但是有個問題是如果一直沒有退票操作線程N(yùn)otify,while語句會一直循環(huán)執(zhí)行下去,CPU消耗巨大

public class SpuriousWakeUp {

static Object lock=newObject();

static? int remainTicketNum=0;

public void buyTicket() {

synchronized(lock) {

while(remainTicketNum<=0) {//if (remainTicketNum<=0)虛假喚醒

try{

lock.wait();

}catch(InterruptedException e) {

e.printStackTrace();

}}

remainTicketNum--;

System.out.println(Thread.currentThread().getName() +"購買成功");

}}

public voidreturnTicket() {

synchronized(lock) {

remainTicketNum++;

lock.notify();

System.out.println(Thread.currentThread().getName() +"退票成功");

}}}

PS:wait方法一定是要獲取到鎖后,才會返回

參考 :

?Java多線程:一道阿里面試題的分析與應(yīng)對

對條件變量(condition variable)的討論

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容