掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
作者:程序員小航 2021-06-30 14:56:12
開發(fā)
前端
分布式
Redis 默認(rèn)的加鎖邏輯是非公平的。在加鎖失敗時(shí),線程會(huì)進(jìn)入 while 循環(huán),一直嘗試獲得鎖,這時(shí)候是多線程進(jìn)行競(jìng)爭(zhēng)。就是說誰搶到就是誰的。

創(chuàng)新互聯(lián)建站專注于企業(yè)營(yíng)銷型網(wǎng)站、網(wǎng)站重做改版、黃山網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5技術(shù)、商城網(wǎng)站定制開發(fā)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)營(yíng)銷網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為黃山等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。
默認(rèn)的加鎖邏輯是非公平的。
在加鎖失敗時(shí),線程會(huì)進(jìn)入 while 循環(huán),一直嘗試獲得鎖,這時(shí)候是多線程進(jìn)行競(jìng)爭(zhēng)。就是說誰搶到就是誰的。
Redisson 提供了公平鎖機(jī)制,使用方式如下:
- RLock fairLock = redisson.getFairLock("anyLock");
- // 最常見的使用方法
- fairLock.lock();
下面一起看下公平鎖是如何實(shí)現(xiàn)的?
相信小伙伴們看過前面的文章,已經(jīng)輕車熟路了,直接定位到源碼方法:RedissonFairLock#tryLockInnerAsync。
好家伙,這一大塊代碼,我截圖也截不完,咱們直接分析 lua 腳本。
PS:雖然咱不懂 lua,但是這一堆堆的 if else 咱們大概還是能看懂的。
因?yàn)?debug 發(fā)現(xiàn) command == RedisCommands.EVAL_LONG,所以直接看下面一部分。
這么長(zhǎng),連呼好幾聲好家伙!
先來看看參數(shù)都有啥?
加鎖隊(duì)列和集合是含有大括號(hào)的字符串。{XXXX} 是指這個(gè) key 僅使用 XXXX 用來計(jì)算 slot 的位置。
上面的 lua 腳本是分為幾塊的,咱們分別從不同的角度看下上面代碼的執(zhí)行。
首次加鎖(Thread1)
第一部分,因?yàn)槭鞘状渭渔i,所以等待隊(duì)列為空,直接 跳出循環(huán)。這一部分執(zhí)行結(jié)束。
第二部分:
執(zhí)行完這里就 return 了。所以后面幾部分就暫時(shí)不看了。
相當(dāng)于下面兩個(gè)命令(整個(gè) lua 腳本都是原子的!):
- > hset anyLock a3da2c83-b084-425c-a70f-5d9a08b37f31:1 1
- > pexpire anyLock 30000
Thread2 加鎖
當(dāng) Thread1 加鎖完成之后,此時(shí) Thread2 來加鎖。
Thread2 可以是本實(shí)例其他線程,也可以是其他實(shí)例的線程。
第一部分,雖然鎖被 Thread1 占用了,但是等待隊(duì)列是空的,直接跳出循環(huán)。
第二部分,鎖存在,直接跳過。
第三部分,線程是否持鎖,沒有持鎖,直接跳過。
第四部分,線程是否在等待隊(duì)列中,Thread2 才來加鎖,不在里面,直接跳過。
Thread2 最后會(huì)來到這里:
zadd KEYS[3] timeout ARGV[2]
這里使用 zadd 命令分別放置的是,redisson_lock_timeout:{anyLock},超時(shí)時(shí)間戳(1624612689520),線程(UUID2:Thread2)。
其中超時(shí)時(shí)間戳當(dāng)分?jǐn)?shù),用來在有序集合中排序,表示加鎖的順序。
Thread3 加鎖
Thread1 占有了鎖,Thread2 在等待,此時(shí)線程 3 來了。
獲取 firstThreadId2 此時(shí)隊(duì)列是有線程的是 UUID2:Thread2。
判斷 firstThreadId2 的分?jǐn)?shù)(超時(shí)時(shí)間戳)是不是小于當(dāng)前時(shí)間戳:
小于等于則說明超時(shí)了,移除 firstThreadId2;
大于,則會(huì)進(jìn)入后續(xù)判斷。
第二、三、四部分都不滿足條件。
Thread3 最后也會(huì)來到這里:
本文主要總結(jié)了公平鎖的加鎖邏輯,這里涉及到比較多的 Redis 操作,做一下簡(jiǎn)要總結(jié):
需要理解的就是這里會(huì)額外添加一個(gè)等待隊(duì)列,以及有序集合。
本文轉(zhuǎn)載自微信公眾號(hào)「程序員小航」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系程序員小航公眾號(hào)。

我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流