<center>Redisson實現分佈式鎖(3)—項目落地實現</center>
有關Redisson實現分佈式鎖前面寫了兩篇博客做爲該項目落地的鋪墊。html
一、Redisson實現分佈式鎖(1)---原理java
二、Redisson實現分佈式鎖(2)—RedissonLockgit
這篇講下經過Redisson實現分佈式鎖的項目實現,我會把項目放到GitHub,該項目能夠直接運用於實際開發中,做爲分佈式鎖使用。github
<font color=#FFD700>1、項目概述 </font>
一、技術架構
項目整體技術選型web
SpringBoot2.1.5 + Maven3.5.4 + Redisson3.5.4 + lombok(插件)
二、加鎖方式
該項目支持 自定義註解加鎖
和 常規加鎖
兩種模式redis
自定義註解加鎖spring
@DistributedLock(value="goods", leaseTime=5) public String lockDecreaseStock(){ //業務邏輯 }
常規加鎖架構
//一、加鎖 redissonLock.lock("redisson", 10); //二、業務邏輯 //三、解鎖 redissonLock.unlock("redisson");
三、Redis部署方式
該項目支持四種Redis部署方式併發
一、單機模式部署 二、集羣模式部署 三、主從模式部署 四、哨兵模式部署
該項目已經實現支持上面四種模式,你要採用哪一種只須要修改配置文件application.properties
,項目代碼不須要作任何修改。app
四、項目總體結構
redis-distributed-lock-core # 核心實現 | ---src | ---com.jincou.redisson |# 經過註解方式 實現分佈式鎖 ---annotation |# 配置類實例化RedissonLock ---config |# 放置常量信息 ---constant |# 讀取application.properties信息後,封裝到實體 ---entity |# 支持單機、集羣、主從、哨兵 代碼實現 ---strategy redis-distributed-lock-web-test # 針對上面實現類的測試類 | ---src | ---java | ---com.jincou.controller |# 測試 基於註解方式實現分佈式鎖 ---AnnotatinLockController.java |# 測試 基於常規方式實現分佈式鎖 ---LockController.java ---resources | # 配置端口號 鏈接redis信息(若是肯定部署類型,那麼將鏈接信息放到core項目中) ---application.properties
<br>
<font color=#FFD700>2、測試 </font>
模擬1秒內100個線程
請求接口,來測試結果是否正確。同時測試3中不一樣的鎖:lock鎖、trylock鎖、註解鎖。
一、lock鎖
/** * 模擬這個是商品庫存 */ public static volatile Integer TOTAL = 10; @GetMapping("lock-decrease-stock") public String lockDecreaseStock() throws InterruptedException { redissonLock.lock("lock", 10); if (TOTAL > 0) { TOTAL--; } Thread.sleep(50); log.info("======減完庫存後,當前庫存===" + TOTAL); //若是該線程還持有該鎖,那麼釋放該鎖。若是該線程不持有該鎖,說明該線程的鎖已到過時時間,自動釋放鎖 if (redissonLock.isHeldByCurrentThread("lock")) { redissonLock.unlock("lock"); } return "================================="; }
壓測結果
沒問題,不會超賣!
二、tryLock鎖
/** * 模擬這個是商品庫存 */ public static volatile Integer TOTAL = 10; @GetMapping("trylock-decrease-stock") public String trylockDecreaseStock() throws InterruptedException { if (redissonLock.tryLock("trylock", 10, 5)) { if (TOTAL > 0) { TOTAL--; } Thread.sleep(50); redissonLock.unlock("trylock"); log.info("====tryLock===減完庫存後,當前庫存===" + TOTAL); } else { log.info("[ExecutorRedisson]獲取鎖失敗"); } return "==================================="; }
測試結果
沒有問題 ,不會超賣!
三、註解鎖
/** * 模擬這個是商品庫存 */ public static volatile Integer TOTAL = 10; @GetMapping("annotatin-lock-decrease-stock") @DistributedLock(value="goods", leaseTime=5) public String lockDecreaseStock() throws InterruptedException { if (TOTAL > 0) { TOTAL--; } log.info("===註解模式=== 減完庫存後,當前庫存===" + TOTAL); return "================================="; }
測試結果
沒有問題 ,不會超賣!
經過實驗能夠看出,經過這三種模式均可以實現分佈式鎖,而後呢?哪一個最優。
<br>
<font color=#FFD700>3、三種鎖的鎖選擇 </font>
觀點
最完美的就是lock鎖,由於
一、tryLock鎖是可能會跳過減庫存的操做,由於當過了等待時間尚未獲取鎖,就會返回false,這顯然很致命! 二、註解鎖只能用於方法上,顆粒度太大,知足不了方法內加鎖。
一、lock PK tryLock 性能的比較
模擬5秒內1000個線程
分別去壓測這兩個接口,看報告結果!
1)lock鎖
壓測結果 1000個線程平均響應時間爲31324。吞吐量 14.7/sec
2)tryLock鎖
壓測結果 1000個線程平均響應時間爲28628。吞吐量 16.1/sec
這裏只是單次測試,有很大的隨機性。從當前環境單次測試來看,tryLock稍微高點。
二、常見異常 attempt to unlock lock, not ······
在使用RedissonLock鎖時,很容易報這類異常,好比以下操做
//設置鎖1秒過去 redissonLock.lock("redisson", 1); /** * 業務邏輯須要諮詢2秒 */ redissonLock.release("redisson");
上面在併發狀況下就會這樣
形成異常緣由:
線程1 進來得到鎖後,但它的業務邏輯須要執行2秒,在 線程1 執行1秒後,這個鎖就自動過時了,那麼這個時候 線程2 進來了得到了鎖。在線程1去解鎖就會拋上面這個異常(由於解鎖和當前鎖已經不是同一線程了)
因此咱們須要注意,設置鎖的過時時間不能設置過小,必定要合理,寧願設置大點。
正對上面的異常,能夠經過isHeldByCurrentThread()方法,
//若是爲false就說明該線程的鎖已經自動釋放,無需解鎖 if (redissonLock.isHeldByCurrentThread("lock")) { redissonLock.unlock("lock"); }
好了,這篇博客就到這了!
至於完整的項目地址見GitHub。
若是對您能有幫助,就給個星星吧,哈哈!
GitHub地址
https://github.com/yudiandemingzi/spring-boot-distributed-redisson <br>
<font color=#FFD700>參考 </font>
<br> <br>
只要本身變優秀了,其餘的事情纔會跟着好起來(中將7)
原文出處:https://www.cnblogs.com/qdhxhz/p/11059200.html