基於redis的一種分布式鎖

2022-08-18 19:45:15 字數 2716 閱讀 7236

前言:本文介紹了一種基於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鎖實現的,至於具體的細節。自己回答的...