各種鎖系列

各種鎖系列

平時我們在開發或學習中,數據庫中,某個編程語言中經常會聽到各種鎖,主要用來對資源併發過程做一些限制,接下來對各種鎖進行一個總結與學習!

樂觀鎖與悲觀鎖

  1. 首先,樂觀鎖與悲觀鎖並不是指具體的某種東西,而是一種設計的思路

  2. 樂觀鎖 (Optimistic Lock)

    • 樂觀鎖表示非常的樂觀,認爲業務操作去拿鎖並不會有什麼問題(衝突),進行完業務操作後需要去更新數據的最後纔去拿鎖

    • 一般數據庫中不自帶樂觀鎖,但是我們要實現樂觀鎖的方式也很簡單,只需要在我們需要鎖的數據上加多一列版本號或者時間戳字段做檢驗就好了

    • 例如: 現在有個商場,我們需要取出商品信息生成訂單,然後去更新狀態,我們只需要直接查詢出商品的記錄(裏面包括了版本號),在需要去更新狀態的時候,就去比較此刻的版本號和之前查詢記錄裏的版本號是否一致,一致就更新狀態和新的版本號,否則則不進行更新

    • 樂觀鎖一般都是用於取鎖失敗概率比較小的場景,不會存在死鎖等問題

      // 查詢
      SELECT data, version AS versionBegin FROM table;
      // 更新時
      UPDATE table SET data = new_data WHERE version = versionBegin;
      if(update_row > 0){
      		// 版本號一致能更新,獲取樂觀鎖成功
      }else{
      		// 版本號不一致,獲取樂觀鎖失敗
      }
    
  3. 悲觀鎖 (Pessimistic Lock)

    • 悲觀鎖則與樂觀鎖相反,比較悲觀認爲每次獲取鎖都有可能失敗,那麼必須先獲取鎖再進行業務操作.

    • 實現一般都是在數據庫加鎖,根據加鎖對象可分爲表鎖或行鎖,按照加鎖的機制不同可分爲共享鎖(讀鎖)和排他鎖(寫鎖)

    • 表鎖與行鎖

      表鎖

      1. InnoDB支持行級鎖,但並不是直接鎖記錄而是鎖索引(使用了主鍵索引就鎖主鍵索引,使用非主鍵索引就先鎖非主鍵索引再鎖主鍵索引),那麼去查找記錄就得掃描全表,就得鎖定表
      2. 開銷大,加鎖慢且會出現死鎖,鎖定力度最小,併發度最高

      行鎖

      1. MyISAM使用的都是表鎖,更新一條記錄就要鎖整個表
      2. 開銷小,加鎖快
    • 共享鎖與排他鎖

      共享鎖(讀鎖)

      1. 加共享鎖:自身可以讀,其他人也可以讀可以繼續加共享鎖,但是不能修改,必須等全部的共享鎖都釋放
      SELECT data FROM table lock in share mode 
      

      排他鎖(寫鎖)

      1. 加排他鎖:自身可以CURD,但是其他人無法操作只能等鎖釋放
      SELECT data FROM table for update
      
    • 那麼實現悲觀鎖,select之後其他事務的修改必須等待事務的結束,其他事務不能對該條記錄進行修改,但樂觀鎖其他事務可以select

      begin
      SELECT data FROM table [lock in share mode // for update];
      
    • 對於UPDATE, INSERT, DELECT語句會自動加排他鎖

公平鎖與非公平鎖

公平鎖就是保障了多線程下各線程獲取鎖的順序,先到的線程優先獲取鎖,而非公平鎖則無法提供這個保障。

分佈式鎖

分佈式鎖: 利用鎖的技術控制在分佈式模型下同一份數據的修改進程數

實現方式

  1. 基於表主鍵唯一的特性做分佈式鎖
    • 對數據庫強依賴,強調數據庫的可用性 => 數據庫主從,一旦掛掉切換備庫
    • 沒有失效時間,一旦解鎖失敗其他線程無法獲得鎖 => 定時任務,定期清路數據庫中超時數據
    • 是非公平鎖,多個線程憑運氣獲得鎖 => 建箇中間表,將等待線程記錄下來,最先創建的允許獲得鎖
    • 是不可重入鎖,沒有釋放鎖之前因爲數據存在無法再次獲得鎖 => 新增字段記錄當前線程信息,如果與請求鎖的線程匹配的話直接分配就好了
  2. 使用上述的樂觀鎖的方式做分佈式鎖
  3. 基於數據庫的排他鎖做分佈式鎖
  4. 基於redis做分佈式鎖
  5. 基於ZOOKEEPER

可重入鎖與不可重入鎖

不可重入鎖: 若當前線程執行中已經獲取了鎖,如果再次獲取該鎖時,就會獲取不到被阻塞。

可重入鎖: 可重入,意味着線程可以進入它已經擁有的鎖的同步代碼塊。

互斥鎖與共享鎖

互斥鎖:同時只能有一個線程獲得鎖。比如,ReentrantLock 是互斥鎖,ReadWriteLock 中的寫鎖是互斥鎖。

共享鎖:可以有多個線程同時或的鎖。比如,Semaphore、CountDownLatch 是共享鎖,ReadWriteLock 中的讀鎖是共享鎖。

其他相關名詞

CAS

CAS是項樂觀鎖技術,當多個線程嘗試使用CAS同時更新同一個變量時,只有其中一個線程能更新變量的值,而其它線程都失敗,失敗的線程並不會被掛起,而是被告知這次競爭中失敗,並可以再次嘗試。

CAS 操作包含三個操作數 —— 內存位置(V)、預期原值(A)和新值(B)。如果內存位置的值與預期原值相匹配,那麼處理器會自動將該位置值更新爲新值。否則,處理器不做任何操作。無論哪種情況,它都會在 CAS 指令之前返回該位置的值。(在 CAS 的一些特殊情況下將僅返回 CAS 是否成功,而不提取當前值。)CAS 有效地說明了“我認爲位置 V 應該包含值 A;如果包含該值,則將 B 放到這個位置;否則,不要更改該位置,只告訴我這個位置現在的值即可。”這其實和樂觀鎖的衝突檢查+數據更新的原理是一樣的。

這裏再強調一下,樂觀鎖是一種思想。CAS是這種思想的一種實現方式

ABA

MVCC

CAP

任何一個分佈式系統都無法同時滿足一致性(Consistency)、可用性(Availability)和分區容錯性(Partition tolerance),最多隻能同時滿足兩項。

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