前言:本文介紹了一種基於redis的分布式鎖,利用jedis實現應用(本文應用於多客戶端+乙個redis的架構,並未考慮在redis為主從架構時的情況)
一、基本原理
1、用乙個狀態值表示鎖,對鎖的占用和釋放通過狀態值來標識。
2、redis採用單程序單執行緒模式,採用佇列模式將併發訪問變成序列訪問,多客戶端對redis的連線並不存在競爭關係。
二、基本命令
1、setnx(set if not exists)
語法:
setnx key value
將 key 的值設為 value ,當且僅當 key 不存在。
若給定的 key 已經存在,則 setnx 不做任何動作。
setnx 是『set if not exists』(如果不存在,則 set)的簡寫
返回值:
設定成功,返回 1 。
設定失敗,返回 0
2、getset
getset key value
將給定 key 的值設為 value ,並返回 key 的舊值(old value)。
當 key 存在但不是字串型別時,返回乙個錯誤。
返回值:
返回給定 key 的舊值。
當 key 沒有舊值時,也即是, key 不存在時,返回 nil 。
3、get
get key
當 key 不存在時,返回 nil ,否則,返回 key 的值。
如果 key 不是字串型別,那麼返回乙個錯誤
三、取鎖、解鎖以及示例**:
/*** @description:分布式鎖,通過控制redis中key的過期時間來控制鎖資源的分配
* 實現思路: 主要是使用了redis 的setnx命令,快取了鎖.
* reids快取的key是鎖的key,所有的共享, value是鎖的到期時間(注意:這裡把過期時間放在value了,沒有時間上設定其超時時間)
* 執行過程:
* 1.通過setnx嘗試設定某個key的值,成功(當前沒有這個鎖)則返回,成功獲得鎖
* 2.鎖已經存在則獲取鎖的到期時間,和當前時間比較,超時的話,則設定新的值
* @param
key *
@param
expiretime 有效時間段長度
* @return
*/public
boolean getlockkey(string key, final
long
expiretime)
else
} else
}/***
* @description: 如果業務處理完,key的時間還未到期,那麼通過刪除該key來釋放鎖
* @param
key *
@param
dealtime 處理業務的消耗時間
* @param
expiretime 失效時間
*/public
void deletelockkey(string key,long dealtime, final
long
expiretime)
}
示例:
//迴圈等待獲取鎖
stringbuilder key = new
stringbuilder(key_pre);
long locktime = 0;
try thread.sleep(200);}}
catch
(interruptedexception e)
//業務邏輯...
//業務邏輯進行完,解鎖
long dellockdatetime =system.currenttimemillis();
long dealtime = dellockdatetime -locktime;
deletelockkey(key.tostring(), dealtime, 60000);
四、一些問題
1、為什麼不直接使用expire設定超時時間,而將時間的毫秒數其作為value放在redis中?
如下面的方式,把超時的交給redis處理:
lock(key, expiresec)
這種方式貌似沒什麼問題,但是假如在setnx後,redis崩潰了,expire就沒有執行,結果就是死鎖了。鎖永遠不會超時。
2、為什麼前面的鎖已經超時了,還要用getset去設定新的時間戳的時間獲取舊的值,然後和外面的判斷超時時間的時間戳比較呢?
因為是分布式的環境下,可以在前乙個鎖失效的時候,有兩個程序進入到鎖超時的判斷。如:
c0超時了,還持有鎖,c1/c2同時請求進入了方法裡面
c1/c2獲取到了c0的超時時間
c1使用getset方法
c2也執行了getset方法
假如我們不加 oldvaluestr.equals(currentvaluestr) 的判斷,將會c1/c2都將獲得鎖,加了之後,能保證c1和c2只能乙個能獲得鎖,乙個只能繼續等待。
注意:這裡可能導致超時時間不是其原本的超時時間,c1的超時時間可能被c2覆蓋了,但是他們相差的毫秒及其小,這裡忽略了
五、不完善之處
1、使用時需要預估業務邏輯處理時間,一旦業務邏輯發生錯誤,那麼只能等到超時之後其他執行緒才能拿到鎖,可能會出現問題
基於redis的分布式鎖
public class redislock 加鎖 取到鎖加鎖,並返回值用於解鎖 取不到鎖則立即返回 1 param millitimeout 最長鎖定時間,超時後自動刪除鎖,避免死鎖 return public synchronized long lock long millitimeout lo...
基於 Redis 的分布式鎖
分布式鎖在分布式應用中應用廣泛,想要搞懂乙個新事物首先得了解它的由來,這樣才能更加的理解甚至可以舉一反三。首先談到分布式鎖自然也就聯想到分布式應用。在我們將應用拆分為分布式應用之前的單機系統中,對一些併發場景讀取公共資源時如扣庫存,賣車票之類的需求可以簡單的使用同步或者是加鎖就可以實現。但是應用分布...
基於Redis的分布式鎖
the real target is that i was asked theredis鎖usage in the interview.and i cann t answer it.真正目的是因為在面試中被問到多執行緒這塊怎麼實現的,當時只是看了下 是用redis鎖實現的,至於具體的細節。自己回答的...