日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

Redisson(2-1)分布式锁实现对比 VS Java的ReentrantLock之tryLock

發(fā)布時(shí)間:2024/3/13 java 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redisson(2-1)分布式锁实现对比 VS Java的ReentrantLock之tryLock 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?Redisson實(shí)現(xiàn)了一整套JDK中ReentrantLock的功能,這里對(duì)比一下實(shí)現(xiàn)的差異和核心的思想。

unfair模式的tryLock

ReentrantLock

①判斷當(dāng)前的state是否是0(初始狀態(tài)),并用原子操作設(shè)置state,成功說(shuō)明獲取鎖,并把當(dāng)前線程設(shè)置為獲取鎖的線程。

②如果state不是0,檢查當(dāng)前線程是否是持有鎖的線程,如果是就按照重入語(yǔ)義,增加計(jì)數(shù),當(dāng)然前提是不能超過(guò)最多重入的次數(shù)(不能溢出),然后將最終計(jì)數(shù)設(shè)置到state中。

③如果既不是①也不是②,那么tryLock失敗。

Redisson

因?yàn)檫@里的鎖是用Redis實(shí)現(xiàn)的,不在Java虛擬機(jī)內(nèi),所以只能用線程id來(lái)辨識(shí)鎖,無(wú)法通過(guò)調(diào)用Thread.currentThread()方法來(lái)做。無(wú)參的加鎖方法,leaseTime是-1,所以走的是if下面的邏輯,這個(gè)加鎖的邏輯是通過(guò)lua腳本來(lái)完成的。這個(gè)和ReentrantLock的加鎖方式不同的是,為了防止死鎖產(chǎn)生(參考上一篇博客),這里設(shè)置了一個(gè)看門狗,默認(rèn)時(shí)間是30秒鐘,如果業(yè)務(wù)沒有處理完,會(huì)每隔10秒鐘延長(zhǎng)這個(gè)鎖的時(shí)間。

具體加鎖的邏輯是通過(guò)lua腳本來(lái)完成,因?yàn)閘ua腳本會(huì)保證原子性。具體的lua腳本內(nèi)容可以參見博客:https://my.oschina.net/u/2313177/blog/1919810。

Lua腳本中的執(zhí)行分為以下三步:

①'exists', KEYS[1]) == 0 //exists檢查redis中是否存在當(dāng)前要獲取的鎖

('hset', KEYS[1], ARGV[2], 1) //如果不存在,則獲取成功;同時(shí)設(shè)置鎖名稱KEYS[1],線程id[ARGV[2],鎖重入次數(shù)1

('hexpire', KEYS[1], ARGV[1]) 設(shè)置鎖的過(guò)期時(shí)間為ARGV[1],返回;

②('hexists', KEYS[1], ARGV[2])?==1? //如果檢查到存在KEYS[1],[ARGV[2],則說(shuō)明獲取成功

('hincrby', KEYS[1], ARGV[2], 1) ?//此時(shí)會(huì)自增對(duì)應(yīng)的value值,記錄重入次數(shù)

('hexpire', KEYS[1], ARGV[1]) //并更新鎖的過(guò)期時(shí)間

③key不存在

('pttl', KEYS[1] ) //直接返回key的剩余過(guò)期時(shí)間

上述一系列操作都是原子性的,所以沒有線程并發(fā)問(wèn)題。

后面還有一段添加listener的操作,因?yàn)樯厦娴膌ua腳本執(zhí)行的redis指令是異步的調(diào)用,會(huì)返回一個(gè)future,這個(gè)future如果成功放回,同時(shí)返回的結(jié)果的Boolean值是true,說(shuō)明獲取鎖成功了,這個(gè)時(shí)候會(huì)調(diào)用一個(gè)叫做scheduleExpirationRenewal的方法:

如果該鎖已經(jīng)添加過(guò)了,那么返回,否則創(chuàng)建一個(gè)延時(shí)任務(wù),該任務(wù)遞歸調(diào)用該任務(wù)本身。最后為了保證競(jìng)態(tài),防止多個(gè)線程同時(shí)寫,會(huì)將寫失敗的線程對(duì)應(yīng)的任務(wù)cancel掉。這個(gè)方法的內(nèi)容在上一篇博客中已經(jīng)解釋了,就是redisson看門狗的作用。

這里有幾個(gè)問(wèn)題需要注意一下:

①為什么說(shuō)這里的返回值Boolean是true,就說(shuō)明獲取鎖成功呢?

這里看下redis指令最后的一個(gè)commands參數(shù):

結(jié)果的Boolean表示的是,返回值不等于null這個(gè)條件是否為真。這里如果Boolean是true,說(shuō)明返回值是null。那么什么情況返回值是null呢?看上面分析的lua腳本,只有當(dāng)當(dāng)前線程id獲取鎖成功的時(shí)候,才會(huì)返回null,否則會(huì)返回ttl。

②tryAcquireAsync和tryAcquireOnceAsync

仔細(xì)看的話,會(huì)發(fā)現(xiàn)tryAcquireAsync中的判斷是否加鎖成功的邏輯和上述邏輯正好相反,

原因是因?yàn)檫@里的commands是

所以返回的就是指令本身,那么根據(jù)上述lua腳本,只有當(dāng)獲取鎖的時(shí)候,返回值才是null,所以這里的判斷雖然和上面相反,但是邏輯本身是一模一樣的。

設(shè)計(jì)成這樣的原因是因?yàn)?#xff0c;帶once的方法需要返回Boolean,一錘子買賣,如果try失敗了再進(jìn)行其他邏輯。而后面的方法,失敗后會(huì)進(jìn)行復(fù)雜的鎖競(jìng)爭(zhēng)處理(這個(gè)后面會(huì)繼續(xù)說(shuō))。

兩者實(shí)現(xiàn)的功能從接口上也能看出不同,前者是:

失敗就失敗了,繼續(xù)按照失敗或成功來(lái)進(jìn)行業(yè)務(wù)邏輯即可。

后者是:

如果沒有立刻獲取到鎖,會(huì)在超時(shí)時(shí)間之內(nèi)進(jìn)行重試等復(fù)雜操作,直到獲取鎖或者超時(shí)為止。

總結(jié)

以上是生活随笔為你收集整理的Redisson(2-1)分布式锁实现对比 VS Java的ReentrantLock之tryLock的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。