redis 分布式鎖的實現
思路: 1)、先判斷沒有,2)、再給裡面放值
1、**第一階段;
public
void
hello()
else
}
問題:加鎖的原子性不能保證
解決:使用redis的setnx
2、**第二階段
setnx->set if not exist:原子操作。判斷帶儲存。
public
void
hello()
else
}
問題:如果由於各種問題(未捕獲的異常、斷電等)導致鎖沒釋放。其他人永遠獲取不到鎖。
解決:加個過期時間。
3、**第三階段
public
void
hello()
else
}
問題:剛拿到鎖,機器炸了,沒來得及設定超時。
解決:加鎖和加超時也必須是原子的。
4、**第四階段:
public
void
hello()
else
}
問題:如果業務邏輯超時,導致鎖自動刪除,業務執行完又刪除一遍鎖。至少多個人都獲取到了鎖。
解決:每個執行緒加鎖設定不同的值 刪鎖時對比 保證刪的是自己加的鎖
5、**第五階段。
public
void
hello()
}else
}
問題:我們獲取鎖的時候,鎖的值正在給我們返回。鎖過期。redis刪除了鎖。但是我們拿到了值,而且對比成功(此時此刻正好有人又獲取)。我們還刪除了鎖。至少兩個執行緒又進入同乙個**。
原因:刪鎖不是原子
解決: lua指令碼進行刪除。
string script =
"if redis.
call
('get'
, keys[1]
)== ar**[
1] then
return redis.
call
('del'
, keys[1]
)else
return
0 end";
jedis.
eval
(script, collections.
singletonlist
(key)
, collections.
singletonlist
(token)
);
1、分布式鎖的核心(保證原子性)
加鎖。佔坑一定要是原子的。(判斷如果沒有,就給redis中儲存值)
鎖要自動超時。
解鎖也要原子。
最終的分布式鎖的**:
@lock
public
void
hello()
else
}
redistemplate和jedis客戶端2選一
@autowired
jedispool jedispool;
public
void
incrdistribute()
"+thread.
currentthread()
.getid()
);}else
catch
(interruptedexception e)
",e);}
}}finally
}
@autowired
stringredistemplate redistemplate;
public
void
incrdistribute()
//刪除鎖
string script =
"if redis.call('get', keys[1]) == ar**[1] then return redis.call('del', keys[1]) else return 0 end"
; defaultredisscript
script1 =
newdefaultredisscript
(script,long.
class);
redistemplate.
execute
(script1, arrays.
aslist
("lock"
),token)
; logger.
info
("刪除鎖成功:{}"
+thread.
currentthread()
.getid()
);}else
}
問題:如果業務執行超時 鎖被自動刪除也是個問題 其他執行緒獲取到鎖進來了也是個問題
解決: 使用守護執行緒 守護執行緒做加時操作 保證過期時間夠用 本執行緒業務執行完成後 守護執行緒加時操作自然結束redisson的看門狗監聽也可以
redis實現分布式鎖有各種問題 建議使用redisson
鎖的更多考慮
1)、自旋。
自旋次數。
自旋超時。
2)、鎖設定
鎖粒度;細;記錄級別;
1)、各自服務各自鎖
2)、分析好粒度,不要鎖住無關資料。一種資料一種鎖,一條資料乙個鎖。
3)、鎖型別
使用jedis springboot整合redis
spring.redis.host=192.168.217.130
spring.redis.jedis.pool.max-active=20
spring.redis.jedis.pool.max-idle=5
pom檔案進入jar包
>
>
redis.clientsgroupid
>
>
jedisartifactid
>
>
3.0.1version
>
dependency
>
新增配置類:
package com.xiepanpan.locks.lockstest.config;
import org.springframework.boot.autoconfigure.data.redis.redisproperties;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
import redis.clients.jedis.jedispool;
import redis.clients.jedis.jedispoolconfig;
/** * @author: xiepanpan
* @date: 2020/2/20
* @description: jedis 配置類
*/@configuration
public
class
jedisconfig
}
分布式鎖 使用Redis實現分布式鎖
關於分布式鎖的實現,我的前一篇文章講解了如何使用zookeeper實現分布式鎖。關於分布式鎖的背景此處不再做贅述,我們直接討論下如何使用redis實現分布式鎖。關於redis,筆主不打算做長篇大論的介紹,只介紹下redis優秀的特性。支援豐富的資料型別,如string list map set zs...
redis實現分布式鎖
隨便 系統越來越大,各功能模組除了垂直切割以外,同時也得做集群處理,那麼問題來了,在多執行緒情況下對於資源的競爭就需要乙個統一的訪問限制。以選課系統為例子,集群中各節點對課程可選數量同時操作,這裡就需要同步了,否則會導致最後選到的數量比可選的數量大,這裡我們的分布式鎖就派上用場了。利用redis來實...
redis實現分布式鎖
分布式鎖可以基於很多種方式實現,比如zookeeper redis.不管哪種方式,他的 基本原理是不變的 用乙個狀態值表示鎖,對鎖的占用和釋放通過狀態值來標識。1 使用redis的setnx命令實現分布式鎖 1 實現的原理 redis為單程序單執行緒模式,採用佇列模式將併發訪問變成序列訪問,且多客戶...