淺談Java分布式架構(gòu)下如何實現(xiàn)分布式鎖
01分布式鎖運用場景
互聯(lián)網(wǎng)秒殺,搶優(yōu)惠卷,接口冪等性校驗。咱們以互聯(lián)網(wǎng)秒殺為例。
@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,但是假如是集群項目呢?搭建的是負(fù)載均衡項目。打開了兩個jvm進程,jvm進程鎖失效。
用nginx做負(fù)載均衡,啟用兩個服務(wù)。進行下壓測。成果和咱們想的相同,用suynchronized關(guān)鍵字加鎖,兩臺服務(wù)器打印的剩下庫存有相同的。所以這種方法并沒有完成線程安全。
02根據(jù)redisson完成分布式鎖
咱們redis中有一個SETNXKEYVALUE,這個指令的時刻復(fù)雜度為O(1),只在鍵key不存在的情況下,將鍵key的值設(shè)置為value,若鍵key現(xiàn)已存在,則setnx指令不做任何操作,指令在設(shè)置成功時返回一,失利時分返回0.
那么咱們能夠簡單用這個指令,完成一個十分簡單的分布式鎖。Springboot結(jié)構(gòu)中咱們運用這個:
stringRedisTemplate.opsForValue().setIfAbsent(),它底層是對setnx的封裝。
這樣完成有什么問題?
假如第一個線程拋了異常中斷了,其它線程就永遠(yuǎn)不能處理了,所以咱們加上trycatch,finally。在finally里面delete咱們存的key值。
假如程序宕機怎么辦?不是可捕獲異常怎么辦?
這時分程序履行到?jīng)]有釋放鎖,即key值一向存在,在發(fā)動web服務(wù)的時分其它線程也一向不等待。這時分會一向存在死鎖,咱們是不是參加鎖的超時時刻是否能夠,即
stringRedisTemplate.expire()
程序迭代的過程是逐步的優(yōu)化,假定我還沒來的及給鎖設(shè)置時長,服務(wù)就宕掉了,這時分該怎么辦。
用兩行指令履行咱們能夠換成一行的指令,及設(shè)置key值的時分,一起設(shè)置時長,stringRedisTemplate.opsForValue().setIfAbsent()。合并成一個原子操作。
這樣寫的化問題還是有的,假如你設(shè)置超時時刻為10秒,而我履行事務(wù)代碼為小于10秒,還沒履行完,就把鎖釋放掉了。高并發(fā)場景下你不能決議履行順序.
能夠不能夠自己加的鎖,自己刪去,別的線程不能進行操作?
咱們給每個線程設(shè)置一個uuid,唯一id。這樣輕輕松松解決了。
商場上面現(xiàn)已有許多許多成熟的結(jié)構(gòu),咱們能夠不需要去手寫分布式結(jié)構(gòu)來完成。
到此這篇關(guān)于淺談Java分布式架構(gòu)下如何實現(xiàn)分布式鎖的文章就介紹到這了,更多相關(guān)Java分布式架構(gòu) 分布式鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot結(jié)合Redis實現(xiàn)序列化的方法詳解
Spring提供了一個RedisTemplate來進行對Redis的操作,但是RedisTemplate默認(rèn)配置的是使用Java本機序列化。如果要對對象操作,就不是那么的方便。所以本文為大家介紹了另一種SpringBoot結(jié)合Redis實現(xiàn)序列化的方法,需要的可以參考一下2022-06-06詳解關(guān)于SpringBoot的外部化配置使用記錄
這篇文章主要介紹了詳解關(guān)于SpringBoot的外部化配置使用記錄,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05關(guān)于Java中static關(guān)鍵字的用法
這篇文章主要介紹了關(guān)于Java中static關(guān)鍵字的用法,static:意為靜態(tài)的,在?Java?里面作為靜態(tài)修飾符,可以理解為全局的意思,static?不僅可以修飾成員變量,成員方法,還可以修飾代碼塊,需要的朋友可以參考下2023-08-08java數(shù)據(jù)結(jié)構(gòu)基礎(chǔ):線性表
這篇文章主要介紹了Java的數(shù)據(jù)解構(gòu)基礎(chǔ),希望對廣大的程序愛好者有所幫助,同時祝大家有一個好成績,需要的朋友可以參考下,希望能給你帶來幫助2021-07-07微信js-sdk+JAVA實現(xiàn)“分享到朋友圈”和“發(fā)送給朋友”功能詳解
本文分享了微信js-sdk+JAVA實現(xiàn)“分享到朋友圈”和“發(fā)送給朋友”功能介紹,大家可以參考一下2018-03-03