死鎖、活鎖、飢餓鎖、無鎖

死鎖、活鎖、飢餓是關於多線程是否活躍出現的運行阻塞障礙問題,如果線程出現了這三種情況,即線程不再活躍,不能再正常地執行下去了。

死鎖

死鎖是多線程中最差的一種情況,多個線程相互佔用對方的資源的鎖,而又相互等對方釋放鎖,此時若無外力干預,這些線程則一直處理阻塞的假死狀態,形成死鎖。

舉個例子,A同學搶了B同學的鋼筆,B同學搶了A同學的書,兩個人都相互佔用對方的東西,都在讓對方先還給自己自己再還,這樣一直爭執下去等待對方還而又得不到解決,老師知道此事後就讓他們相互還給對方,這樣在外力的干預下他們才解決,當然這只是個例子沒有老師他們也能很好解決,計算機不像人如果發現這種情況沒有外力干預還是會一直阻塞下去的。

死鎖產生條件

  • 互斥條件:所謂互斥就是進程在某一時間內獨佔資源。
  • 請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。
  • 不剝奪條件:進程已獲得資源,在末使用完之前,不能強行剝奪。
  • 循環等待條件:若干進程之間形成一種頭尾相接的循環等待資源關係。

死鎖解決辦法

  • 如果併發查詢多個表,約定訪問順序。
  • 在同一個事務中,儘可能做到一次鎖定獲取所需要的資源。
  • 對於容易產生死鎖的業務場景,嘗試升級鎖顆粒度,使用表級鎖。
  • 採用分佈式事務鎖或者使用樂觀鎖。

活鎖

多線程中出現了相互謙讓,都主動將資源釋放給別的線程使用,這樣資源在多個線程之間跳動而又得不到執行,形成活鎖。

活鎖這個概念大家應該很少有人聽說或理解它的概念,而在多線程中這確實存在。活鎖恰恰與死鎖相反,死鎖是大家都拿不到資源都佔用着對方的資源,而活鎖是拿到資源卻又相互釋放不執行。當多線程中出現了相互謙讓,都主動將資源釋放給別的線程使用,這樣這個資源在多個線程之間跳動而又得不到執行,這就是活鎖。

飢餓

一個或者多個線程因爲種種原因無法獲得所需要的資源,導致一直無法執行的狀態。多線程中優先級高的會優先執行,並且搶佔優先級低的資源,導致優先級低的線程無法得到執行。

我們知道多線程執行中有線程優先級這個東西,優先級高的線程能夠插隊並優先執行,這樣如果優先級高的線程一直搶佔優先級低線程的資源,導致低優先級線程無法得到執行,這就是飢餓。當然還有一種飢餓的情況,一個線程一直佔着一個資源不放而導致其他線程得不到執行,與死鎖不同的是飢餓在以後一段時間內還是能夠得到執行的,如那個佔用資源的線程結束了並釋放了資源。

與死鎖不同的是,飢餓鎖在一段時間內,優先級低的線程最終還是會執行的,比如高優先級的線程執行完之後釋放了資源。

無鎖

無鎖,即沒有對資源進行鎖定,即所有的線程都能訪問並修改同一個資源,但同時只有一個線程能修改成功。

無鎖典型的特點就是一個修改操作在一個循環內進行,線程會不斷的嘗試修改共享資源,如果沒有衝突就修改成功並退出否則就會繼續下一次循環嘗試。所以,如果有多個線程修改同一個值必定會有一個線程能修改成功,而其他修改失敗的線程會不斷重試直到修改成功。之前的文章我介紹過JDK的CAS原理及應用即是無鎖的實現。

可以看出,無鎖是一種非常良好的設計,它不會出現線程出現的跳躍性問題,鎖使用不當肯定會出現系統性能問題,雖然無鎖無法全面代替有鎖,但無鎖在某些場合下是非常高效的。


Kotlin開發者社區

專注分享 Java、 Kotlin、Spring/Spring Boot、MySQL、redis、neo4j、NoSQL、Android、JavaScript、React、Node、函數式編程、編程思想、"高可用,高性能,高實時"大型分佈式系統架構設計主題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章