執行緒虛假喚醒問題

2021-10-24 07:32:53 字數 3694 閱讀 1893

執行緒通訊中可能存在虛假喚醒問題,關於虛假喚醒的概念,我覺得官方文件說得不太清晰,下面通過乙個例子簡單說明:

現在有兩個方法,乙個+1,乙個-1,每個方法開啟2個執行緒迴圈執行10次;

**實現

public

class

test},

"a")

.start()

;new

thread((

)->},

"b")

.start()

;new

thread((

)->},

"c")

.start()

;new

thread((

)->},

"d")

.start()

;}}class

data

catch

(interruptedexception e)

} number++

; system.out.

println

(thread.

currentthread()

.getname()

+"=>"

+number)

;//通知其他執行緒

this

.notifyall()

;}//-1的方法

public

synchronized

void

decrement()

catch

(interruptedexception e)

} number--

; system.out.

println

(thread.

currentthread()

.getname()

+"=>"

+number)

;//通知其他執行緒

this

.notifyall();}}

+1的方法中,判斷number值是否為0,如果不為0呼叫執行緒等待的方法,如果為0 number值+1,控制台列印執行緒名稱的number值,然後通知其他執行緒;-1的方法同理;

我們的預期是控制台交替列印40條記錄,每條記錄的結果是執行緒名 + 0或者1;

執行的結果:

a=>1

b=>0

a=>1

b=>0

a=>1

b=>0

a=>1

b=>0

a=>1

b=>0

a=>1

b=>0

c=>1

a=>2

c=>3

b=>2

b=>1

b=>0

c=>1

a=>2

c=>3

b=>2

d=>1

d=>0

c=>1

a=>2

c=>3

d=>2

d=>1

d=>0

c=>1

a=>2

c=>3

d=>2

d=>1

d=>0

c=>1

d=>0

c=>1

d=>0

結果發現number值出現2和3,這就是執行緒虛假喚醒造成的問題,那為什麼會這樣?官方文件是這樣解釋的:

我看著很頭大,只知道要把+1-1方法中的 if 換成while;

if 換while輸入的結果

a=>1

b=>0

a=>1

b=>0

a=>1

b=>0

a=>1

b=>0

a=>1

b=>0

a=>1

b=>0

a=>1

b=>0

a=>1

b=>0

a=>1

b=>0

a=>1

b=>0

c=>1

d=>0

c=>1

d=>0

c=>1

d=>0

c=>1

d=>0

c=>1

d=>0

c=>1

d=>0

c=>1

d=>0

c=>1

d=>0

c=>1

d=>0

c=>1

d=>0

這樣就可以了,那為什麼呢?

if 語句的判斷只會執行一次,當滿足條件進入執行緒等待,執行緒被喚醒後直接執行下面的**;

上面有段輸入的記錄是這樣的:

d=

>0c=

>1a=

>2c=

>3b=

>

2

d執行緒執行完-1的方法後,c和a執行緒處同時被喚醒,都執行+1的方法,c執行緒先+1,所以a執行緒會輸出2;

此時c執行緒比較猛,在a執行緒執行+1的方法時,它已經搶到cpu資源執行到執行緒等待這一步了,a執行緒執行完又把c執行緒喚醒,c執行緒執行number++,所以輸入了3;

while 語句會一直迴圈判斷,當滿足條件進入執行緒等待,並且一直迴圈判斷;

還是上面 if 語句 那段異常輸入的記錄,看看while會怎樣執行;

d執行緒執行完-1的方法後,c和a執行緒同時被喚醒,此時c執行了+1的方法,number=1;

現在用了while方法,a執行緒會迴圈判斷 number != 0,此時條件成立,a執行緒繼續進入執行緒等待;

所以不會有上面那種情況;

當有兩條執行緒呼叫相同的方法時,執行緒喚醒呼叫了notifyall()方法,會喚醒所有執行緒,這兩條執行緒都會被喚醒,如果用if會直接執行下一步的**,如果用while,執行緒雖然被喚醒,但還是會進行迴圈判斷,就避免了執行緒虛假喚醒的問題;

那我們使用notify()方法可不可,notify()方法是喚醒下乙個執行緒,只喚醒乙個;

還是上面的例子,當a執行緒執行完呼叫notify()喚醒其他執行緒,此時number = 1,如果喚醒的是c執行緒,c執行緒判斷number != 0,進入執行緒等待,會一直卡在這裡;所以用notify()方法是不行的;

實際開發中,我們也很少在乙個方法中執行兩條呼叫同個方法的執行緒(上面的例子如果每個方法只開啟一條執行緒不會出現執行緒虛假喚醒的情況);在多執行緒中,常用while判斷而不是if

執行緒的虛假喚醒

所謂虛假喚醒字面意思理解就是執行緒在被喚醒後,執行緒執行等待的變數條件實際上仍然不滿足,這種情況發生在兩個以上的多執行緒生產者消費者問題中。從乙個實際的例子中來理解虛假喚醒,建立乙個簡單的消費者生產者模型,判斷條件時共享資源number是否等於0,等於0時,生產者讓其 1,不等於0時,消費者讓其 1...

java 執行緒 通知 虛假喚醒

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

8 27 虛假喚醒

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