摘要:併發訪問共享資源,若是不加鎖,可能會致使數據不一致問題,一般爲了解決併發訪問問題,咱們都會在訪問共享資源以前加鎖,保證同一時刻只有一個線程訪問。下面咱們用問答的方式說明下各類併發鎖的概念、優缺點及其應用場景。
本文分享自華爲雲社區《一文帶你全面理解各類鎖機制》,原文做者:dayu_dls。mysql
併發訪問共享資源,若是不加鎖,可能會致使數據不一致問題,一般爲了解決併發訪問問題,咱們都會在訪問共享資源以前加鎖,保證同一時刻只有一個線程訪問。下面咱們用問答的方式說明下各類併發鎖的概念、優缺點及其應用場景。sql
互斥鎖和自旋鎖是最底層的兩種鎖,其餘的不少鎖都是基於他們的實現。當線程A獲取到鎖後,線程B再去獲取鎖,有兩種處理方式,第一種是線程B循環的去嘗試獲取鎖,直到獲取成功爲止即自旋鎖,另外一種是線程B放棄獲取鎖,在鎖空閒時,等待被喚醒,即互斥鎖。編程
互斥鎖會釋放當前線程的cpu,致使加鎖的代碼阻塞,直到線程再次被喚醒。互斥鎖加鎖失敗時,會從用戶態陷入到內核態,讓內核幫咱們切換線程,存在必定的性能開銷。segmentfault
而自旋鎖會自用戶態由應用程序完成,不涉及用戶態到內核態的轉化,沒有線程上下文切換,性能相對較好。自旋鎖加鎖過程:多線程
自旋鎖會利用cpu一直工做直到獲取到鎖,中間不會釋放cpu,但若是被鎖住的代碼執行時間較長,致使cpu空轉,浪費資源。併發
讀寫鎖由讀鎖和寫鎖組成。讀鎖又稱爲共享鎖,S鎖,寫鎖又稱爲排它鎖、X鎖,在mysql的事務中大量使用。寫鎖是獨佔鎖,一旦線程獲取寫鎖,其餘線程不能獲取寫鎖和讀鎖。性能
讀鎖是共享鎖,當線程獲取讀鎖,其餘線程能夠獲取讀鎖不能獲取寫鎖。由於併發數據讀取並不會改變共享數據致使數據不一致。讀寫鎖把對共享資源的讀操做和寫操做分別加鎖控制,可以提升讀線程的併發性,適用於讀多寫少的場景。線程
讀優先鎖但願的是讀鎖可以被更多的線程獲取,能夠提升讀線程的併發性。線程A獲取了讀鎖,線程B想獲取寫鎖,此時會被阻塞,線程c能夠繼續獲取讀鎖,直到A和c釋放鎖,線程B才能夠獲取寫鎖。若是有不少線程獲取讀鎖,且加鎖的代碼執行時間很長,就到致使線程B永遠獲取不到寫鎖。blog
寫優先鎖但願的是寫鎖可以被優先獲取。線程A獲取了讀鎖,線程B想獲取寫鎖,此時會被阻塞,後面獲取讀鎖都會失敗,線程A釋放鎖,線程B能夠獲取寫鎖,其餘獲取讀鎖的線程阻塞。若是有不少寫線程獲取寫鎖,且加鎖的代碼執行時間很長,就到致使讀線程永遠獲取不到讀鎖。隊列
上面兩種鎖都會形成【飢餓】現象,爲解決這種問題,能夠增長一個隊列,把獲取鎖的線程(無論是寫線程仍是讀線程)按照先進先出的方式排隊,每次從隊列中取出一個線程獲取鎖,這種獲取鎖的方式是公平的。
樂觀鎖是先修改共享資源,再用歷史數據和當前數據比對驗證這段時間共享數據有沒有被修改,若是沒有被修改,那麼更新數據,若是有其餘線程更新了共享資源,須要從新獲取數據,再更新,驗證,循環往復的重試,直到更新成功。因此當數據更新操做比較頻繁,數據衝突的機率就會比較大,重試的次數就會多,浪費CPU資源。
樂觀鎖其實全程沒有加鎖,也叫無鎖編程,因此針對讀多寫少的場景,併發性能較高,典型的實現MVCC,mysql中會使用MVCC構建一致性讀來保證可重複讀。悲觀鎖是在訪問共享資源以前通通加鎖。當併發衝突機率較高時,樂觀鎖不在適用,悲觀鎖就排上用場。互斥鎖、自旋鎖都是悲觀鎖的實現。