01分布式鎖運用場景
互聯網秒殺,搶優惠卷,介面冪等性校驗,咱們以互聯網秒殺為例,
@RestController
@Slf4j
publicclassIndexController{
@Autowired
privateRedissonredission;
@Autowired
privateStringRedisTemplatestringRedisTemplate;
@RequestMapping("/deduct_stock")
publicStringdeductStock()throwsInterruptedException{
intstock=Integer.parseInt
(stringRedisTemplate.opsForValue().get("stock"));
if(stock>0){
intrealStock=stock-1;
stringRedisTemplate.opsForValue().set("stock",realStock+"");
log.info("扣減成功,剩下庫存+"+realStock);
}else{
return"庫存不足";
}
return"end";
}
}
上面代碼假定多個執行緒一起進來,讀到胡成果相同,寫入的成果也相同,造成多個減庫存操作,只減少了一次,
好多人想到的處理方式是加synchronized,但是假如是集群專案呢?搭建的是負載均衡專案,打開了兩個jvm行程,jvm行程鎖失效,
用nginx做負載均衡,啟用兩個服務,進行下壓測,成果和咱們想的相同,用suynchronized關鍵字加鎖,兩臺服務器列印的剩下庫存有相同的,所以這種方法并沒有完成執行緒安全,
02根據redisson完成分布式鎖
咱們redis中有一個SETNXKEYVALUE,這個指令的時刻復雜度為O(1),只在鍵key不存在的情況下,將鍵key的值設定為value,若鍵key現已存在,則setnx指令不做任何操作,指令在設定成功時回傳一,失利時分回傳0.
那么咱們能夠簡單用這個指令,完成一個十分簡單的分布式鎖,Springboot結構中咱們運用這個:
stringRedisTemplate.opsForValue().setIfAbsent(),它底層是對setnx的封裝,
這樣完成有什么問題?
假如第一個執行緒拋了例外中斷了,其它執行緒就永遠不能處理了,所以咱們加上trycatch,finally,在finally里面delete咱們存的key值,
假如程式宕機怎么辦?不是可捕獲例外怎么辦?
這時分程式履行到沒有釋放鎖,即key值一向存在,在發動web服務的時分其它執行緒也一向不等待,這時分會一向存在死鎖,咱們是不是參加鎖的超時時刻是否能夠,即
stringRedisTemplate.expire()
程式迭代的程序是逐步的優化,假定我還沒來的及給鎖設定時長,服務就宕掉了,這時分該怎么辦,
用兩行指令履行咱們能夠換成一行的指令,及設定key值的時分,一起設定時長,stringRedisTemplate.opsForValue().setIfAbsent(),合并成一個原子操作,
這樣寫的化問題還是有的,假如你設定超時時刻為10秒,而我履行事務代碼為小于10秒,還沒履行完,就把鎖釋放掉了,高并發場景下你不能決議履行順序.
能夠不能夠自己加的鎖,自己刪去,別的執行緒不能進行操作?
咱們給每個執行緒設定一個uuid,唯一id,這樣輕輕松松解決了,
商場上面現已有許多許多成熟的結構,咱們能夠不需要去手寫分布式結構來完成,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/141397.html
標籤:Java
