目的和實驗復現前提
- 基于 Redis 實作一個通用的分布式鎖組件,
- 前提
- jmeter: Java進階系列:使用Jmeter進行并發測驗
- nginx: 常見中間件安裝陳述句中的nginx安裝陳述句
- idea:開發工具
整體模式

- Jmeter發壓到Nginx上,Nginx在負載到兩臺應用上,應用去redis上扣款,組成分布式環境,
- 注意在實驗的時候,可以打包兩個埠不同的jar包,也可以在idea上開啟Allow parallel run達到實驗目的,
- SpringBoot jar啟動報錯:SpringApplication類找不到 和 沒有主清單錯誤解決
主要關注點
- 【互斥】
- 因為是分布式情況,所以synchronized失效,
- 多執行緒同時訪問同一個變數的時候,需要保持互斥,使用redis的setnx來實作,
- 【鎖釋放】
- 如果執行程序中出現問題,那么無法釋放鎖?
- 使用try-catch-finally,在finally中釋放鎖
- 如果finally沒有執行,怎么辦?
- 給鎖加時間,到期自動釋放
- 同時為了保證原子性,獲取鎖和給鎖加時間,應該是原子操作
- 代碼復用問題
- 加解鎖代碼做成介面和實作類
- 因為互斥,鎖需要做成單例
- 如何保證/控制該類的加解鎖順序是匹配的?
- 比如A執行緒呼叫了加鎖方法,B執行緒呼叫了解鎖方法
- 生成uuid做憑據,加鎖時,生成uuid放入redission的value值,解鎖時,獲取redission的alue值與執行緒的uuid比較,相同則釋放鎖,以此來保證同一把鎖
- 因為鎖類是單例的,uuid在加鎖方法內是隨即生成的,所以存在執行緒安全問題多執行緒訪問的時候,呼叫加鎖方法,會產生多個uuid,setnx未失效前,訪問回傳false,雖然獲取鎖失敗,但是存在重寫uuid的可能,所以uuid必須放在threadlocal中,
- 又因為thread復用問題,存在threadlocal污染的問題,結束時,需要remove,
- 如果執行程序中出現問題,那么無法釋放鎖?
- 【支持阻塞和非阻塞】
- 阻塞:獲取不到鎖,直接return false
- 非阻塞:加鎖程序寫成while回圈
- 【可重入性】
- 先判斷鎖是否存在,不存在則創建鎖,
- 存在,則依據threadlocal的uuid來判斷是否為同一把鎖,同鎖準入,
- 【鎖超時】
- 業務執行時間遠大于鎖的生效時間,
- 設定守護執行緒,異步續時
- 解鎖時,關閉守護續時執行緒
- 創建執行緒時,將該守護執行緒的執行緒號放入uuid,
- 釋放鎖的時候,通過uuid獲取執行緒號,做interrupt,
- 業務執行時間遠大于鎖的生效時間,
具體實作
- 見專案原始碼:DistributedLock_Redis
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/166434.html
標籤:其他
