Java鎖的一些認知

同一個進程

1.重入鎖(ReentrantLock)

使用ReentrantLock獲取鎖的時候會判斷當前線程是否爲獲取鎖的線程,如果是則將同步的狀態+1,釋放鎖的時候將同步的狀態-1,只有將同步狀態的次數爲0時纔會最終釋放鎖。

重入鎖:一個線程獲得了鎖之後仍然可以反覆加鎖,而不會出現自己阻塞自己的情況。

2.讀寫鎖

使用ReentrantReadWriteLock,同時維護一對鎖:讀鎖和寫鎖,當寫線程訪問時其他所有鎖都將阻塞,讀線程訪問時則不會。通過將讀寫鎖分離可以很大程度的提高併發量和吞吐量。

不同進程

分佈式鎖:

  1. 基於 DB 的唯一索引。
    可以創建一張表,將其中的某個字段設置爲唯一索引,當多個請求多來的時候只有新建記錄成功的請求才算獲取到鎖,當使用完畢後刪除這條記錄的時候即釋放鎖。
    存在的問題:
  • 數據庫單點的問題,掛了怎麼辦?
  • 不是重入鎖,同一個進程無法在釋放鎖之前再次獲取鎖,因爲數據庫中已經存在了一條記錄了
  • 鎖是非阻塞的,一旦insert失敗則會立即返回,並不會進入阻塞隊列只能下一次在獲取
  • 鎖沒有失效時間,如果那個進程解鎖失敗那就沒有請求可以再次獲取鎖了

解決方案:

  • 數據庫切換爲主從,不存在單點。
  • 在表中加入一個同步狀態字段,每次獲得鎖的時候加1,釋放鎖的時候減1,當狀態值爲0時就刪除這一條記錄,即釋放鎖。
  • 非阻塞的情況可以用while循環來實現,循環的時候記錄時間,達到X秒標記爲超時,break;
  • 可以開啓一個定時任務每個一段時間掃描找出過了X秒都沒有被刪除的記錄,主動刪除這條記錄。
  1. 基於 ZK 的臨時有序節點。
    可以參考:
    Zookeeper 分佈式鎖
  2. 基於 Redis 的 NX EX 參數。
    使用setnX(key) setEX(timeout)命令,只有在該key不存在的時候纔會創建這個key,就相當於獲取了鎖。由於有超時時間,所以過了規定時間會自動刪除,這樣也可以避免死鎖。
    可以參考:
    Redlock(redis分佈式鎖)原理分析
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章