redisson特性及優(yōu)雅實(shí)現(xiàn)示例
redisson的幾大特性
相信看了這個標(biāo)題的同學(xué),對這個問題以已經(jīng)非常不陌生了,信手拈來redisson的幾大特性:
可重入性
【多個業(yè)務(wù)線同一時刻n條扣款,如果用setnx,我怎么監(jiān)控的加鎖解鎖線程?死鎖不得發(fā)生吶?】
redisson使用hash結(jié)構(gòu),業(yè)務(wù)名稱作為key,uuid+線程id作為field,加鎖次數(shù)作為value,這不就解決上述問題了嗎
阻塞能力
【加鎖有兩個策略,一是互斥,二是阻塞?;コ獗热缯f定時任務(wù),同一時刻我需要只執(zhí)行一次就行。阻塞的話-例如多個業(yè)務(wù)線同一時刻n條扣款,我不能互斥掉吧,那不得被噴死。我得寫個while死循環(huán)【標(biāo)準(zhǔn)用語就是自旋】一段時間在獲取一次,保證系統(tǒng)都能處理這些請求】
續(xù)約
加鎖過期時間短-加鎖邏輯還沒執(zhí)行完就解鎖了是不是很尷尬,過長的話-宕機(jī)恢復(fù)時間又變長
redisson默認(rèn)30秒給你執(zhí)行,30秒沒執(zhí)行完就續(xù)約30s,宕機(jī)的話恢復(fù)時間也不會太長。
原理呢就是使用了netty的時間輪實(shí)現(xiàn)。簡單點(diǎn)說就是環(huán)形數(shù)組。
直通車:
RedissonLock --> renewExpiration -->TimerTask Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask() { @Override public void run(Timeout timeout) throws Exception { ExpirationEntry ent = EXPIRATION_RENEWAL_MAP.get(getEntryName()); if (ent == null) { return; } Long threadId = ent.getFirstThreadId(); if (threadId == null) { return; } RFuture<Boolean> future = renewExpirationAsync(threadId); future.onComplete((res, e) -> { if (e != null) { log.error("Can't update lock " + getName() + " expiration", e); return; } if (res) { // reschedule itself renewExpiration(); } }); } }, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS); // internalLockLeaseTime默認(rèn)30s,因此這里默認(rèn)延遲10s后執(zhí)行 // 其中TimerTask引用的就是netty中的TimerTask
初始化timer的代碼
protected void initTimer(MasterSlaveServersConfig config) { int[] timeouts = new int[]{config.getRetryInterval(), config.getTimeout()}; Arrays.sort(timeouts); int minTimeout = timeouts[0]; if (minTimeout % 100 != 0) { minTimeout = (minTimeout % 100) / 2; } else if (minTimeout == 100) { minTimeout = 50; } else { minTimeout = 100; } // 就是分成了1024個格子,每個格子默認(rèn)100ms timer = new HashedWheelTimer(new DefaultThreadFactory("redisson-timer"), minTimeout, TimeUnit.MILLISECONDS, 1024, false); connectionWatcher = new IdleConnectionWatcher(this, config); subscribeService = new PublishSubscribeService(this, config); }
大白話講就是:例如將一個圓分成4等分,1,2,3,4,從1到2需要100ms,那么我需要計算延遲500ms需要走幾步,下標(biāo)是多少?
既然是時間總要跳動嘛,沒猜錯就是sleep??
- 紅鎖
如果redis節(jié)點(diǎn)宕機(jī)大部分節(jié)點(diǎn)同意獲取鎖,才能獲取到鎖。
- 聯(lián)鎖
全部節(jié)點(diǎn)加鎖成功才算加鎖成功。
- 加鎖流程
lua判斷鎖是否存在
--> 不存在創(chuàng)建hash,當(dāng)前業(yè)務(wù)key,uuid+線程id為field,value =1 ,設(shè)置過期時間并返回
--> 存在檢查uuid+線程id是否一致,一致遞增value更新過期時間返回。存在鎖檢查uuid+線程id不一致,判斷是否到期,沒到期我就幫你續(xù)期,自己加鎖也沒有成功,就以當(dāng)前業(yè)務(wù)key發(fā)布消息訂閱pubsub,等收到解鎖消息在重試
- 解鎖邏輯
lua判斷鎖是否存在
-->不存在則直接發(fā)布解鎖消息并返回
-->存在就檢查uuid+線程id是否一致,不一致就報錯,因為加鎖線程不一致。如果一致,就遞減value,判斷是否大于0,如果等于0,刪除key并發(fā)布解鎖消息
以上就是redisson特性及優(yōu)雅實(shí)現(xiàn)示例的詳細(xì)內(nèi)容,更多關(guān)于redisson特性及實(shí)現(xiàn)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot集成本地緩存性能之王Caffeine示例詳解
這篇文章主要為大家介紹了SpringBoot集成本地緩存性能之王Caffeine的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07Java使用備忘錄模式實(shí)現(xiàn)過關(guān)類游戲功能詳解
這篇文章主要介紹了Java使用備忘錄模式實(shí)現(xiàn)過關(guān)類游戲功能,結(jié)合實(shí)例形式詳細(xì)分析了java備忘錄模式的概念、原理及其在過關(guān)類游戲中的具體應(yīng)用方法,需要的朋友可以參考下2018-04-04spring?@value無法取值多個properties文件的解決
這篇文章主要介紹了spring?@value無法取值多個properties文件的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03Java實(shí)現(xiàn)提取不重復(fù)的整數(shù)實(shí)例
這篇文章主要介紹了Java實(shí)現(xiàn)提取不重復(fù)的整數(shù)實(shí)例,具有一定借鑒價值,需要的朋友可以參考下2017-12-12Java?Stream實(shí)現(xiàn)多字段分組groupingBy操作詳解
Stream是Java8的一個新特性,主要用戶集合數(shù)據(jù)的處理,如排序、過濾、去重等等功能,本文就來講講如何利用Stream實(shí)現(xiàn)比較優(yōu)雅的按多字段進(jìn)行分組groupingBy吧2023-06-06JAVA進(jìn)階之HashMap底層實(shí)現(xiàn)解析
Hashmap是java面試中經(jīng)常遇到的面試題,大部分都會問其底層原理與實(shí)現(xiàn),為了能夠溫故而知新,特地寫了這篇文章,以便時時學(xué)習(xí)2021-11-11SpringBoot定時調(diào)度之Timer與Quartz詳解
Java?中常用的定時調(diào)度框架有以下幾種:Timer、ScheduledExecutorService、Spring?Task和Quartz,本文主要來和大家講講他們的具體使用,需要的可以參考一下2023-06-06