使用setnx命令,在SpringBoot中爲setIfAbsent,最簡單的代碼以下:redis
固然上述代碼會存在問題,如A服務在執行到中間時拋異常,則不能釋放這個鎖,加上try-catch-finally,以下:架構
可是若是在中間的時候直接斷掉,則仍然不能釋放鎖,加上鎖的自動釋放時間,以下:併發
可是這個不能保證原子性,若是在正好執行到設置過時時間以前斷掉,則仍然不能釋放鎖,放在一條執行語句裏面,以下:框架
可是在高併發狀況下,線程一須要15秒,線程二須要8秒,線程一執行到第十秒會自動釋放鎖,這時線程二會拿到鎖,線程二執行了五秒後,線程一也執行了五秒,這時一會執行finally裏的代碼釋放鎖,可是這個鎖倒是二的,這時線程三又會拿到這個鎖去執行。。。如此下去會永久失效分佈式
解決問題的根本點:本身的鎖被別人釋放掉高併發
解決方式:使用惟一id,只有是本身的鎖纔會本身去釋放代碼以下:性能
可是這裏仍然會有超時問題,設置短了太容易超時,設置長了不利於鎖的釋放。lua
使用從線程定時任務去執行監控主線程看看是否還在執行,若是是,則從新把超時時間延長,這也是一種解決方式。spa
使用框架一步解決問題:線程
實現原理以下圖:
裏面的lock方法的最核心部分就是執行了一個lua腳本,保證了加鎖和設置過時時間的原子性,原理如上圖
上圖所示的redis是主從架構,當Master宕機可是仍然未同步到從節點的時候,從節點會選舉出新的主節點,可是這是沒有加鎖的,這是由於Redission的分佈式鎖是知足AP的,即知足可用性,不知足一致性,只要主節點寫了一個key,立馬告訴redission客戶端(不一樣於zookeeper的分佈式鎖是知足CP,zookeeper主節點獲取key以後,超過半數的從節點同步以後纔會返回,即知足一致性)
這個問題使用redis的Redlock能夠解決(原理和zookeeper相似),可是犧牲了性能,並不推薦使用