Redis鎖的簡單應用

2022-09-15 05:21:14 字數 4043 閱讀 4325

蝸牛redis系列文章目錄

redis cluster

其實說多執行緒修改資料也不合適,畢竟redis服務端是單執行緒的,所有命令序列執行,只是在客戶端併發傳送命令的時候,導致序列的命令一些排列問題和網路時間差等造成資料不一致。本文雖然是數字的加減,但是為了說明鎖的情況,故意不是用原子命令incr。也並非分布式鎖的正確實現,沒有考慮一些重入性等,稍後會整理一篇分布式鎖的實踐。

redis分布式鎖 

zk+curator 分布式鎖 

先配上乙個簡易的redishelper,乙個set值,乙個get值,乙個設定併發鎖,以便在我後面的操作中,你能清楚我究竟做了什麼。

public class redishelper

public t get(string key)

public idisposable acquire(string key)

}

下面看一下併發**,我只new了兩個thread。兩個執行緒同時想訪問同乙個key,分別訪問五萬次,在併發條件下,我們很難保證資料的準確性,請比較輸出結果。

static void main(string args)

public static void addval()

console.writeline("執行緒結束,輸出" + rds.get("mykey1"));

是的,和我們單執行緒,跑兩個50000,會輸出100000。現在是兩個併發執行緒同時跑在由於併發造成的資料結果往往不是我們想要的。那麼如何解決這個問題呢,redis已經為我們準備好了!

你可以看到我redishelper中有個方法是public idisposable acquire(string key)。也可以看到他返回的是idisposable,證明我們需要手動釋放資源。方法內部的acquirelock正是關鍵之處,它像redis中索取一把鎖頭,被鎖住的資源,只能被單個執行緒訪問,不會被兩個執行緒同時get或者set,這兩個執行緒一定是交替著進行的,當然這裡的交替並不是指你一次我一次,也可能是你多次,我一次,下面看**。

static void main(string args)

public static void addval()

}console.writeline("執行緒結束,輸出" + rds.get("mykey1"));

}

可以看到我使用了using,呼叫我的acquire方法獲取鎖。

輸出結果最後是100000,正是我們要的正確結果。前面的8w+是因為兩個執行緒之一先執行結束了。

還有,在正式使用的過程中,建議給我們的鎖,使用後刪除掉,並加上乙個過期時間,使用expire。

以免程式執行期間意外退出,導致鎖一直存在,今後可能無法更新或者獲取此被鎖住的資料。

你也可以嘗試一下不設定expire,在程式剛開始執行時,關閉console,重新執行程式,並且在redis-cli的操作控制台,get你鎖住的值,將會永遠獲取不到。

所有連線此redis例項的機器,同一時刻,只能有乙個獲取指定name的鎖.

下面是stackexchange.redis的寫法

var info = "name-"+environment.machinename;

//如果5秒不釋放鎖 自動釋放。避免死鎖

if (db.locktake("name", info, timespan.fromseconds(5)))

catch (exception ex)

finally

}

蝸牛redis系列文章目錄

redis cluster

其實說多執行緒修改資料也不合適,畢竟redis服務端是單執行緒的,所有命令序列執行,只是在客戶端併發傳送命令的時候,導致序列的命令一些排列問題和網路時間差等造成資料不一致。本文雖然是數字的加減,但是為了說明鎖的情況,故意不是用原子命令incr。也並非分布式鎖的正確實現,沒有考慮一些重入性等,稍後會整理一篇分布式鎖的實踐。

redis分布式鎖 

zk+curator 分布式鎖 

先配上乙個簡易的redishelper,乙個set值,乙個get值,乙個設定併發鎖,以便在我後面的操作中,你能清楚我究竟做了什麼。

public class redishelper

public t get(string key)

public idisposable acquire(string key)

}

下面看一下併發**,我只new了兩個thread。兩個執行緒同時想訪問同乙個key,分別訪問五萬次,在併發條件下,我們很難保證資料的準確性,請比較輸出結果。

static void main(string args)

public static void addval()

console.writeline("執行緒結束,輸出" + rds.get("mykey1"));

是的,和我們單執行緒,跑兩個50000,會輸出100000。現在是兩個併發執行緒同時跑在由於併發造成的資料結果往往不是我們想要的。那麼如何解決這個問題呢,redis已經為我們準備好了!

你可以看到我redishelper中有個方法是public idisposable acquire(string key)。也可以看到他返回的是idisposable,證明我們需要手動釋放資源。方法內部的acquirelock正是關鍵之處,它像redis中索取一把鎖頭,被鎖住的資源,只能被單個執行緒訪問,不會被兩個執行緒同時get或者set,這兩個執行緒一定是交替著進行的,當然這裡的交替並不是指你一次我一次,也可能是你多次,我一次,下面看**。

static void main(string args)

public static void addval()

}console.writeline("執行緒結束,輸出" + rds.get("mykey1"));

}

可以看到我使用了using,呼叫我的acquire方法獲取鎖。

輸出結果最後是100000,正是我們要的正確結果。前面的8w+是因為兩個執行緒之一先執行結束了。

還有,在正式使用的過程中,建議給我們的鎖,使用後刪除掉,並加上乙個過期時間,使用expire。

以免程式執行期間意外退出,導致鎖一直存在,今後可能無法更新或者獲取此被鎖住的資料。

你也可以嘗試一下不設定expire,在程式剛開始執行時,關閉console,重新執行程式,並且在redis-cli的操作控制台,get你鎖住的值,將會永遠獲取不到。

所有連線此redis例項的機器,同一時刻,只能有乙個獲取指定name的鎖.

下面是stackexchange.redis的寫法

var info = "name-"+environment.machinename;

//如果5秒不釋放鎖 自動釋放。避免死鎖

if (db.locktake("name", info, timespan.fromseconds(5)))

catch (exception ex)

finally

}

redis鎖的實際應用

以前對redis上鎖概念一直不太清楚,現在來整理下 其實就是當你的一次操作要保證資料的原子性和一致性,你需要先加個鎖 這個加鎖的動作其實也包含了驗證是否上鎖 然後進行操作,完了即使沒有成功也要解鎖,這個redis的操作為什麼要用lua語句因為要保證原子操作 解鎖的原則 在乙個使用者下 如下示例 lo...

redis的簡單應用

我這裡將 中某些會被使用者經常檢視的商品的詳細資訊儲存到redis中示例 1.首先我們需要在linux中安裝redis服務。2.啟動redis服務 redis server 3.在專案中配置spring整合redis的配置檔案 spring redis.xml 4.在後台查詢商品詳細資訊的時候,我們...

redis事務及鎖應用

redis事務及鎖應用 redis支援簡單的事務 redis與mysql事務的對比 redis mysql 開啟multi start transaction 語句普通命令 普通sql 失敗discard取消 rollback回滾 成功exec commit 注 rollback與discard的區...