做開發,這幾種鎖機制你不得不了解一下


摘要:並發訪問共享資源,如果不加鎖,可能會導致數據不一致問題,通常為了解決並發訪問問題,我們都會在訪問共享資源之前加鎖,保證同一時刻只有一個線程訪問。下面我們用問答的方式說明下各種並發鎖的概念、優缺點及其應用場景。

本文分享自華為雲社區《一文帶你全面理解各種鎖機制》,原文作者:dayu_dls。

並發訪問共享資源,如果不加鎖,可能會導致數據不一致問題,通常為了解決並發訪問問題,我們都會在訪問共享資源之前加鎖,保證同一時刻只有一個線程訪問。下面我們用問答的方式說明下各種並發鎖的概念、優缺點及其應用場景。

1、什么是互斥鎖和自旋鎖,各有什么優缺點?

互斥鎖和自旋鎖是最底層的兩種鎖,其他的很多鎖都是基於他們的實現。當線程A獲取到鎖后,線程B再去獲取鎖,有兩種處理方式,第一種是線程B循環的去嘗試獲取鎖,直到獲取成功為止即自旋鎖,另一種是線程B放棄獲取鎖,在鎖空閑時,等待被喚醒,即互斥鎖。

互斥鎖會釋放當前線程的cpu,導致加鎖的代碼阻塞,直到線程再次被喚醒。互斥鎖加鎖失敗時,會從用戶態陷入到內核態,讓內核幫我們切換線程,存在一定的性能開銷。

  • (1)當線程加鎖失敗,內核會把線程的狀態由“運行”設置為“睡眠”,讓出cpu;
  • (2)當鎖空閑時,內核喚醒線程,狀態設置為“就緒”,獲取cpu執行;

而自旋鎖會自用戶態由應用程序完成,不涉及用戶態到內核態的轉化,沒有線程上下文切換,性能相對較好。自旋鎖加鎖過程:

  • (1)查看鎖的狀態;
  • (2)鎖空閑,獲取鎖,否則執行(1);

自旋鎖會利用cpu一直工作直到獲取到鎖,中間不會釋放cpu,但如果被鎖住的代碼執行時間較長,導致cpu空轉,浪費資源。

2、什么是讀寫鎖?

讀寫鎖由讀鎖和寫鎖組成。讀鎖又稱為共享鎖,S鎖,寫鎖又稱為排它鎖、X鎖,在mysql的事務中大量使用。寫鎖是獨占鎖,一旦線程獲取寫鎖,其他線程不能獲取寫鎖和讀鎖。

讀鎖是共享鎖,當線程獲取讀鎖,其他線程可以獲取讀鎖不能獲取寫鎖。因為並發數據讀取並不會改變共享數據導致數據不一致。讀寫鎖把對共享資源的讀操作和寫操作分別加鎖控制,能夠提高讀線程的並發性,適用於讀多寫少的場景。

3、什么是讀優先鎖、寫優先鎖、公平讀寫鎖?

讀優先鎖希望的是讀鎖能夠被更多的線程獲取,可以提高讀線程的並發性。線程A獲取了讀鎖,線程B想獲取寫鎖,此時會被阻塞,線程c可以繼續獲取讀鎖,直到A和c釋放鎖,線程B才可以獲取寫鎖。如果有很多線程獲取讀鎖,且加鎖的代碼執行時間很長,就到導致線程B永遠獲取不到寫鎖。

寫優先鎖希望的是寫鎖能夠被優先獲取。線程A獲取了讀鎖,線程B想獲取寫鎖,此時會被阻塞,后面獲取讀鎖都會失敗,線程A釋放鎖,線程B可以獲取寫鎖,其他獲取讀鎖的線程阻塞。如果有很多寫線程獲取寫鎖,且加鎖的代碼執行時間很長,就到導致讀線程永遠獲取不到讀鎖。

上面兩種鎖都會造成【飢餓】現象,為解決這種問題,可以增加一個隊列,把獲取鎖的線程(不管是寫線程還是讀線程)按照先進先出的方式排隊,每次從隊列中取出一個線程獲取鎖,這種獲取鎖的方式是公平的。

4、什么是樂觀鎖和悲觀鎖?

樂觀鎖是先修改共享資源,再用歷史數據和當前數據比對驗證這段時間共享數據有沒有被修改,如果沒有被修改,那么更新數據,如果有其他線程更新了共享資源,需要重新獲取數據,再更新,驗證,循環往復的重試,直到更新成功。所以當數據更新操作比較頻繁,數據沖突的概率就會比較大,重試的次數就會多,浪費CPU資源。

樂觀鎖其實全程沒有加鎖,也叫無鎖編程,所以針對讀多寫少的場景,並發性能較高,典型的實現MVCC,mysql中會使用MVCC構建一致性讀來保證可重復讀。悲觀鎖是在訪問共享資源之前統統加鎖。當並發沖突概率較高時,樂觀鎖不在適用,悲觀鎖就排上用場。互斥鎖、自旋鎖都是悲觀鎖的實現。

 

點擊關注,第一時間了解華為雲新鮮技術~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM