鎖的一些概念

(1)同一進程

重入鎖

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

讀寫鎖

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

(2)不同進程(分佈式鎖)

基於數據庫

可以創建一張表,將其中的某個字段設置爲唯一索引,當多個請求過來的時候只有新建記錄成功的請求才算獲取到鎖,當使用完畢刪除這條記錄的時候即釋放鎖。

存在的問題:

  • 數據庫單點問題,掛了怎麼辦?
  • 不是重入鎖,同一進程無法在釋放鎖之前再次獲得鎖,因爲數據庫中已經存在了一條記錄了。
  • 鎖是非阻塞的,一旦 insert 失敗則會立即返回,並不會進入阻塞隊列只能下一次再次獲取。
  • 鎖沒有失效時間,如果那個進程解鎖失敗那就沒有請求可以再次獲取鎖了。

解決方案:

  • 數據庫切換爲主從,不存在單點。
  • 在表中加入一個同步狀態字段,每次獲取鎖的是加 1 ,釋放鎖的時候-1,當狀態爲 0 的時候就刪除這條記錄,即釋放鎖。
  • 非阻塞的情況可以用 while 循環來實現,循環的時候記錄時間,達到 X 秒記爲超時,break
  • 可以開啓一個定時任務每隔一段時間掃描找出多少 X 秒都沒有被刪除的記錄,主動刪除這條記錄。

基於 Redis

使用 setNX(key) setEX(timeout) 命令,只有在該 key 不存在的時候創建這個 key,就相當於獲取了鎖。由於有超時時間,所以過了規定時間會自動刪除,這樣也可以避免死鎖。

可以參考:

基於 Redis 的分佈式鎖

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