Java執行緒鎖 二 迴圈列印ABC

2021-07-23 15:54:55 字數 2490 閱讀 6660

1、經典例子

對object.wait(),object.notify()的應用最經典的例子,應該是三線程列印abc的問題了吧,這是一道比較經典的面試題(網上關於本面試題很多),題目要求如下:

建立三個執行緒,a執行緒列印10次a,b執行緒列印10次b,c執行緒列印10次c,要求執行緒同時執行,交替列印10次abc。這個問題用object的wait(),notify()就可以很方便的解決。**如下:

public

class

mythreadprinter2

implements

runnable

@override

public

void

run()

try catch (interruptedexception e)

}}

}

public

static

void

main(string args) throws exception

}

先來解釋一下其整體思路,從大的方向上來講,該問題為三線程間的同步喚醒操作,主要的目的就是threada->threadb->threadc->threada迴圈執行三個執行緒。為了控制線程執行的順序,那麼就必須要確定喚醒、等待的順序,所以每乙個執行緒必須同時持有兩個物件鎖,才能繼續執行。乙個物件鎖是prev,就是前乙個執行緒所持有的物件鎖。還有乙個就是自身物件鎖。

主要的思想就是,為了控制執行的順序,必須要先持有prev鎖,也就前乙個執行緒要釋放自身物件鎖,再去申請自身物件鎖,兩者兼備時列印,之後首先呼叫self.notify()釋放自身物件鎖,喚醒下乙個等待執行緒,再呼叫prev.wait()釋放prev物件鎖,終止當前執行緒,等待迴圈結束後再次被喚醒。

執行上述**,可以發現三個執行緒迴圈列印abc,共10次。程式執行的主要過程就是a執行緒最先執行,持有c,a物件鎖,後釋放a,c鎖,喚醒b。執行緒b等待a鎖,再申請b鎖,後列印b,再釋放b,a鎖,喚醒c,執行緒c等待b鎖,再申請c鎖,後列印c,再釋放c,b鎖,喚醒a。看起來似乎沒什麼問題,但如果你仔細想一下,就會發現有問題,就是初始條件,三個執行緒按照a,b,c的順序來啟動,按照前面的思考,a喚醒b,b喚醒c,c再喚醒a。但是這種假設依賴於jvm中線程排程、執行的順序。具體來說就是,在main主線程啟動threada後,需要在threada執行完,在prev.wait()等待時,再切回執行緒啟動threadb,threadb執行完,在prev.wait()等待時,再切回主線程,啟動threadc,只有jvm按照這個執行緒執行順序執行,才能保證輸出的結果是正確的。而這依賴於jvm的具體實現。

考慮一種情況,如下:如果主線程在啟動a後,執行a,過程中又切回主線程,啟動了threadb,threadc,之後,由於a執行緒尚未釋放self.notify,也就是b需要在synchronized(prev)處等待,而這時c卻呼叫synchronized(prev)獲取了對b的物件鎖。這樣,在a呼叫完後,同時threadb獲取了prev也就是a的物件鎖,threadc的執行條件就已經滿足了,會列印c,之後釋放c,及b的物件鎖,這時threadb具備了執行條件,會列印b,也就是迴圈變成了acbacb了。這種情況,可以通過在run中主動釋放cpu,來進行模擬。**如下:

public

void

run()

catch (interruptedexception e)

self.notify();

}

try catch (interruptedexception e)

}

}

}

執行後的列印結果就變成了acbacb了。為了避免這種與jvm排程有關的不確定性。需要讓a,b,c三個執行緒以確定的順序啟動,最終**如下:

public

class

mythreadprinter2

implements

runnable

@override

public

void

run()

catch (interruptedexception e)

self.notify();

}

try catch (interruptedexception e)

}

}

}

public

static

void

main(string args) throws exception

}

這樣才可以完美的解決該問題。通過這個例子也是想說明一下,很多理論、概念如obj.wait(),obj.notify()等,理解起來,比較簡單,但是在實際的應用當中,這裡卻是往往出現問題的地方。需要更加深入的理解。並在解決問題的過程中不斷加深對概念的掌握。

JAVA多執行緒列印ABC

多執行緒中乙個很有名的例題就是多執行緒列印 abc,要求用三個執行緒,分別是列印 a,列印 b,列印 c,輪流喚醒和鎖死,最終列印出10組 abc。created by 123 on 2016 8 30.public class printabc 將列印a,列印b,列印c分別列為三個互斥的方法,寫在...

java 多執行緒列印ABC

方法千千中,開始看到這個,我立馬想到了cyclicbarrier,能讓abc在列印在一組,可是控制不了abc列印的順序 後來自己用了乙個最簡單的synchronize的迴圈實現了,可以感覺沒什麼成就感 package dirk.zhang public class printabc class th...

java 多執行緒列印ABC

方法千千中,開始看到這個,我立馬想到了cyclicbarrier,能讓abc在列印在一組,可是控制不了abc列印的順序 後來自己用了乙個最簡單的synchronize的迴圈實現了,可以感覺沒什麼成就感 package dirk.zhang public class printabc class th...