1. 程式人生 > >Java多執行緒的死鎖,活鎖,飢餓

Java多執行緒的死鎖,活鎖,飢餓

死鎖:是指兩個或兩個以上的程序(或執行緒)在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的程序稱為死鎖程序。

死鎖發生在當一些程序請求其他程序佔有的資源而被阻塞時。


死鎖發生的四個條件
1、互斥條件:執行緒對資源的訪問是排他性的,如果一個執行緒對佔用了某資源,那麼其他執行緒必須處於等待狀態,直到資源被釋放。
2、請求和保持條件:執行緒T1至少已經保持了一個資源R1佔用,但又提出對另一個資源R2請求,而此時,資源R2被其他執行緒T2佔用,於是該執行緒T1也必須等待,但又對自己保持的資源R1不釋放。
3、不剝奪條件:執行緒已獲得的資源,在未使用完之前,不能被其他執行緒剝奪,只能在使用完以後由自己釋放。
4、環路等待條件:在死鎖發生時,必然存在一個“程序-資源環形鏈”,即:{p0,p1,p2,...pn},程序p0(或執行緒)等待p1佔用的資源,p1等待p2佔用的資源,pn等待p0佔用的資源。(最直觀的理解是,p0等待p1佔用的資源,而p1而在等待p0佔用的資源,於是兩個程序就相互等待)

活鎖:
是指執行緒1可以使用資源,但它很禮貌,讓其他執行緒先使用資源,執行緒2也可以使用資源,但它很紳士,也讓其他執行緒先使用資源。這樣你讓我,我讓你,最後兩個執行緒都無法使用資源。
活鎖不會被阻塞,而是不停檢測一個永遠不可能為真的條件。除去程序本身持有的資源外,活鎖狀態的程序會持續耗費寶貴的CPU時間

關於“死鎖與活鎖”的比喻:
死鎖:迎面開來的汽車A和汽車B過馬路,汽車A得到了半條路的資源(滿足死鎖發生條件1:資源訪問是排他性的,我佔了路你就不能上來,除非你爬我頭上去),汽車B佔了汽車A的另外半條路的資源,A想過去必須請求另一半被B佔用的道路(死鎖發生條件2:必須整條車身的空間才能開過去,我已經佔了一半,尼瑪另一半的路被B佔用了),B若想過去也必須等待A讓路,A是輛蘭博基尼,B是開奇瑞QQ的屌絲,A素質比較低開窗對B狂罵:快給老子讓開,B很生氣,你媽逼的,老子就不讓(死鎖發生條件3:在未使用完資源前,不能被其他執行緒剝奪),於是兩者相互僵持一個都走不了(死鎖發生條件4:環路等待條件),而且導致整條道上的後續車輛也走不了。
例如:馬路中間有條小橋,只能容納一輛車經過,橋兩頭開來兩輛車A和B,A比較禮貌,示意B先過,B也比較禮貌,示意A先過,結果兩人一直謙讓誰也過不去。

飢餓:
是指如果執行緒T1佔用了資源R,執行緒T2又請求封鎖R,於是T2等待。T3也請求資源R,當T1釋放了R上的封鎖後,系統首先批准了T3的請求,T2仍然等待。然後T4又請求封鎖R,當T3釋放了R上的封鎖之後,系統又批准了T4的請求......,T2可能永遠等待。


關於”飢餓“的比喻:

在“首堵”北京的某一天,天氣陰沉,空氣中充斥著霧霾和地溝油的味道,某個苦逼的臨時工交警正在處理塞車,有兩條道A和B上都堵滿了車輛,其中A道堵的時間最長,B相對相對堵的時間較短,這時,前面道路已疏通,交警按照最佳分配原則,示意B道上車輛先過,B道路上過了一輛又一輛,A道上排隊時間最長的確沒法通過,只能等B道上沒有車輛通過的時候再等交警發指令讓A道依次通過,這也就是ReentrantLock顯示鎖裡提供的不公平鎖機制(當然了,ReentrantLock也提供了公平鎖的機制,由使用者根據具體的使用場景而決定到底使用哪種鎖策略),不公平鎖能夠提高吞吐量但不可避免的會造成某些執行緒的飢餓。

阻塞

圖片轉自http://f.dataguru.cn/thread-541686-1-1.html(博主很用心,圖片生動形象)