執行緒的虛假喚醒

2021-09-28 23:42:49 字數 2163 閱讀 3632

所謂虛假喚醒字面意思理解就是執行緒在被喚醒後,執行緒執行等待的變數條件實際上仍然不滿足,這種情況發生在兩個以上的多執行緒生產者消費者問題中。

從乙個實際的例子中來理解虛假喚醒,建立乙個簡單的消費者生產者模型,判斷條件時共享資源number是否等於0,等於0時,生產者讓其+1,不等於0時,消費者讓其-1。

public

class

pretendnotify

,string.

valueof

(i))

.start()

;}for(

int i =

0; i <

3; i++

),string.

valueof

(i))

.start()

;}}}

//共享資源類

class

sharedate

// 執行生產任務並喚醒消費執行緒

number++

; system.out.

println

(thread.

currentthread()

.getname()

+"執行了生產任務,此時number="

+number)

; condition.

signalall()

;}catch

(exception e)

finally

}// 消費

public

void

consume()

// 執行消費任務並喚醒消費執行緒

number--

; system.out.

println

(thread.

currentthread()

.getname()

+"執行了消費任務,此時number="

+number)

; condition.

signalall()

;}catch

(exception e)

finally

}}

執行一下,結果如下:

0執行了生產任務,此時number=

12不滿足生產條件,暫時掛起

1不滿足生產條件,暫時掛起

0執行了消費任務,此時number=

02執行了生產任務,此時number=

11執行了生產任務,此時number=

21執行了消費任務,此時number=

12執行了消費任務,此時number=

0

這裡問題就出現了,正常情況下應該是生產線程執行一次,消費執行緒執行一次,而此時卻出現了munber=2的情況,從控制台的結果可以看出執行的過程,0號生產者執行緒在執行完生產任務後,2號生產者執行緒獲得了鎖,由於此時的number並沒有被消費,所以判斷條件 if (number == 0)為false,2號生產線程被掛起,同樣的1號生產線程獲得了鎖,此時number還沒有被消費,所以也被掛起。

然後0號消費者執行緒執行了消費任務,喚醒了生產者執行緒,被掛起的1號和2號生產者執行緒被掛起的位置是在執行了if判斷語句之後,所以被喚醒的時候直接就執行了生產任務,而不會再經過判斷,這是number=2出現的原因。

在這裡,執行緒1就是被虛假喚醒的,因為生產者執行緒1和執行緒2同時被喚醒後,執行緒2先執行了生產任務,這個時候執行緒1其實是不滿足生產條件的,也就是被虛假喚醒的。解決方法在jdk文件中也給出了

synchronized

(obj)

也就是使用while迴圈判斷,執行緒被喚醒後要再次驗證判斷條件再執行,將上面的demo中的if()判斷修改後,再次執行結果為:

0執行了生產任務,此時number=

11不滿足生產條件,暫時掛起

2不滿足生產條件,暫時掛起

0執行了消費任務,此時number=

01執行了生產任務,此時number=

12不滿足生產條件,暫時掛起

1執行了消費任務,此時number=

02執行了生產任務,此時number=

12執行了消費任務,此時number=

0

執行緒虛假喚醒問題

在執行緒通訊中可能存在虛假喚醒問題,關於虛假喚醒的概念,我覺得官方文件說得不太清晰,下面通過乙個例子簡單說明 現在有兩個方法,乙個 1,乙個 1,每個方法開啟2個執行緒迴圈執行10次 實現 public class test a start new thread b start new thread...

java 執行緒 通知 虛假喚醒

1 synchronized 鎖定的是當前物件的成員變數,也就是說無論當前物件有幾個synchronized 塊,他們使用的是同意個鎖,乙個物件只有乙個鎖 2 notifyall 之後不會立馬去喚醒而是等當前 執行結束之後才回去喚醒 class product productqty system.o...

8 27 虛假喚醒

什麼情況下會導致虛假喚醒 當執行緒是使用 if 對鎖進行判斷而不是while 在第一次判斷標誌位的時候條件成立進入 wait 方法,然後當別的執行緒喚醒這個執行緒的時候,它就不會再去判斷一次標誌位而是直接往下執行了,這樣一來,當有多個執行相同功能的執行緒在 wait 方法中等待的時候,一旦這些執行緒...