1、synchronized處理併發的缺點?
(1)速度比較慢,無法做到細粒度的控制。
(2)只適合單機的情況,不適合集群。
2、分布式鎖的實現方案
分布式鎖一般有三種實現方式:
(1). 資料庫樂觀鎖;
(2) 基於redis的分布式鎖;
(3). 基於zookeeper的分布式鎖
3、分布式鎖的保障條件
為了確保分布式鎖可用,我們至少要確保鎖的實現同時滿足以下四個條件:
(1)互斥性。在任意時刻,只有乙個客戶端能持有鎖。
(2)不會發生死鎖。即使有乙個客戶端在持有鎖的期間崩潰而沒有主動解鎖,也能保證後續其他客戶端能加鎖。
(3)具有容錯性。只要大部分的redis節點正常執行,客戶端就可以加鎖和解鎖。
(4)解鈴還須繫鈴人。加鎖和解鎖必須是同乙個客戶端,客戶端自己不能把別人加的鎖給解了。
4、基於redis的分布式鎖實現(商品秒殺場景的解決方案)
redis為單程序單執行緒模式,採用佇列模式將併發訪問變成序列訪問,且多客戶端對redis的連線並不存在競爭關係,redis的setnx命令可以方便的實現分布式鎖。
1)setnx(set if not exists)將 key 的值設為 value ,當且僅當 key 不存在。若給定的 key 已經存在,則 setnx 不做任何動作。
setnx 是『set if not exists』(如果不存在,則 set)的簡寫。
返回值:
設定成功,返回
1 。返回1,則該客戶端獲得鎖,把lock.foo的鍵值設定為時間值表示該鍵已被鎖定,該客戶端最後可以通過del lock.foo來釋放該鎖
設定失敗,返回
0 。返回0,表明該鎖已被其他客戶端取得,這時我們可以先返回或進行重試等對方完成或等待鎖超時。
2)getset(先get再set,get舊值,set新值)
將給定 key 的值設為 value ,並返回 key 的舊值(old value)。
當 key 存在但不是字串型別時,返回乙個錯誤。
返回值:
返回給定
key 的舊值。
當 key 沒有舊值時,也即是,
key 不存在時,返回
nil 。
描述:set()加入了nx引數,可以保證如果已有key存在,則函式不會呼叫成功,也就是只有乙個客戶端能持有鎖,滿足互斥性。
其次,由於我們對鎖設定了過期時間,即使鎖的持有者後續發生崩潰而沒有解鎖,鎖也會因為到了過期時間而自動解鎖(即key被刪除),不會發生死鎖。
面試題:redis分布式鎖如何實現的:
主要利用setnx和getset命令來實現的。
setnx主要是利用保證乙個客戶端可以獲取到該鎖即保證互斥性。
我們會在setnx設定key的value值設定乙個時間,這個時間是我們可以設定為當前時間+過期時間,即總共執行緒可以保留該鎖的時間。
如果該時間過期,則另外有執行緒訪問的時候,則利用getset方法來進行獲取原來的時間和設定新的value值,判斷下是否可以獲取該鎖。如果獲取了該鎖則下乙個執行緒進來的時候就不可以獲取該鎖了。這樣避免了死鎖同時也可以防止多個執行緒同時獲取鎖。
主要redis的setnx和getset這兩個命令。
主要有兩步操作:加鎖和解鎖
初步計畫在此段**新增加鎖和解鎖的功能:
redis的分布式鎖**:
加鎖和解鎖是在乙個類中:
加鎖:
解鎖:
處理併發的加鎖和解鎖後的業務**:
問題:1、為什麼不直接使用expire設定超時時間,而將時間的毫秒數其作為value放在redis中?
redis expire 命令用於設定 key 的過期時間。key 過期後將不再可用。
expirekey_name time_in_seconds 例如:expire runooobkey 60,設定60s後過期。
答案:假如在setnx後,redis崩潰了,expire就沒有執行,結果就是死鎖了,鎖永遠不會超時。
2、為什麼前面的鎖已經超時了,還要用getset去設定新的時間戳的時間獲取舊的值,然後和外面的判斷超時時間的時間戳比較呢?
因為是分布式的環境下,可以在前乙個鎖失效的時候,有兩個程序進入到鎖超時的判斷。如:
c0超時了,還持有鎖,c1/c2同時請求進入了方法裡面
c1/c2獲取到了c0的超時時間
c1使用getset方法
c2也執行了getset方法
假如我們不加 oldvaluestr.equals(currentvaluestr) 的判斷,將會c1/c2都將獲得鎖,加了之後,能保證c1和c2只能乙個能獲得鎖,乙個只能繼續等待。
注意:這裡可能導致超時時間不是其原本的超時時間,c1的超時時間可能被c2覆蓋了,但是他們相差的毫秒及其小,這裡忽略了。
redis分布式鎖
redis分布式鎖 直接上 我寫了四個redis分布式鎖的方法,大家可以提個意見 第一種方法 redis分布式鎖 param timeout public void lock long timeout thread.sleep 100 catch exception e override publi...
Redis分布式鎖
分布式鎖一般有三種實現方式 1.資料庫樂觀鎖 2.基於redis的分布式鎖 3.基於zookeeper的分布式鎖.首先,為了確保分布式鎖可用,我們至少要確保鎖的實現同時滿足以下四個條件 互斥性。在任意時刻,只有乙個客戶端能持有鎖。不會發生死鎖。即使有乙個客戶端在持有鎖的期間崩潰而沒有主動解鎖,也能保...
redis分布式鎖
使用redis的setnx命令實現分布式鎖 redis為單程序單執行緒模式,採用佇列模式將併發訪問變成序列訪問,且多個客戶端對redis的連線並不存在競爭關係。redis的setnx命令可以方便的實現分布式鎖。setnx key value 將key的值設為value,當且僅當key不存在。如給定的...