前言
分布式鎖是一種悲觀鎖
楼眷,至少要確保鎖的實(shí)現(xiàn)同時(shí)滿足以下四個(gè)條件:
-
互斥性
: 在任意時(shí)刻,只有一個(gè)客戶端(進(jìn)程)能持有鎖。(UUID奸远、重入鎖) -
不會(huì)發(fā)生死鎖
: 即使有一個(gè)客戶端在持有鎖的期間崩潰而沒有主動(dòng)解鎖磅氨,也能保證后續(xù)其他客戶端能加鎖尺栖。(超時(shí),臨時(shí)節(jié)點(diǎn)) -
具有容錯(cuò)性
: 只要大部分的Redis節(jié)點(diǎn)正常運(yùn)行烦租,客戶端就可以加鎖和解鎖延赌。(redis cluster) -
解鈴還須系鈴人
。加鎖和解鎖必須是同一個(gè)客戶端叉橱,客戶端自己不能把別人加的鎖給解了挫以。
問題:一旦加了分布式鎖之后,對(duì)同一個(gè)商品(按商品加鎖)的下單請(qǐng)求窃祝,會(huì)導(dǎo)致所有客戶端都必須對(duì)同一個(gè)商品的庫存鎖key進(jìn)行加鎖掐松。這樣會(huì)導(dǎo)致對(duì)同一個(gè)商品的下單請(qǐng)求,就必須串行化,一個(gè)接一個(gè)的處理大磺。
思考:在高并發(fā)場(chǎng)景下如何優(yōu)化分布式鎖的并發(fā)性能抡句?
實(shí)現(xiàn)方式
如果大家了解ConcurrentHashMap的源碼和底層原理,應(yīng)該知道里面的核心思路杠愧,就是分段加鎖待榔!
- 把數(shù)據(jù)分成多段,每段是一個(gè)單獨(dú)的鎖流济,所以多個(gè)線程過來并發(fā)修改數(shù)據(jù)的時(shí)候究抓,可以并發(fā)的修改不同段的數(shù)據(jù)。不至于說袭灯,同一時(shí)間只能有一個(gè)線程獨(dú)占修改ConcurrentHashMap中的數(shù)據(jù)刺下。
- Java 8中新增了一個(gè)LongAdder類,也是針對(duì)Java 7以前的AtomicLong進(jìn)行的優(yōu)化稽荧,解決的是CAS類操作在高并發(fā)場(chǎng)景下橘茉,使用樂觀鎖思路,會(huì)導(dǎo)致大量線程長(zhǎng)時(shí)間重復(fù)循環(huán)姨丈。
- LongAdder中也是采用了類似的分段CAS操作畅卓,失敗則自動(dòng)遷移到下一個(gè)分段進(jìn)行CAS的思路。
不足
- 首先蟋恬,得對(duì)一個(gè)數(shù)據(jù)分段存儲(chǔ)翁潘,一個(gè)庫存字段本來好好的,現(xiàn)在要分為多個(gè)分段庫存字段歼争;
- 其次拜马,在每次處理庫存的時(shí)候,還得自己寫隨機(jī)算法沐绒,隨機(jī)挑選一個(gè)分段來處理俩莽;
- 最后,如果某個(gè)分段中的數(shù)據(jù)不足了乔遮,你還得自動(dòng)切換到下一個(gè)分段數(shù)據(jù)去處理扮超。