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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Redisson(2-3)分布式锁实现对比 VS Java的ReentrantLock的FairLock

發布時間:2024/3/13 java 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redisson(2-3)分布式锁实现对比 VS Java的ReentrantLock的FairLock 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?Redisson實現了一整套JDK中ReentrantLock的功能,這里對比一下公平鎖(Fair)實現的差異和核心的思想。

?

公平鎖存在的意義是為了保證絕對的公平,但是有其弊端,這個在網上有很多相關的解釋,就是說絕對的公平不一定是性能最高的,因此和它相對的還有非公平鎖,但是費公平鎖也有問題,會引發饑餓現象。具體解釋也可參見AbstractQueuedSynchronizer(九)——ReentrantLock公平和非公平鎖_普通網友的博客-CSDN博客

fair模式的帶超時時間的tryLock(超時時間)

ReentrantLock

ReentrantLock實現公平鎖依賴的是一個叫做hasQueuedPredecessors的方法,所有的加鎖操作前都要先判斷這個方法的返回值,

方法的注釋寫的很清楚:

檢驗是否有其他線程已經等待了更長時間,借此保證公平。此外,注釋還寫道:

這兩個&&判斷也可以實現同樣的功能,同時語義更清晰,但是效率相比之下沒有前者的數據結構操作高。

總結下來,單虛擬機內部的公平操作依仗的是鏈表數據結構的幫助,將所有申請鎖的線程按照訪問的優先級排序,從而保證了這些申請鎖的線程得到鎖的公平性。那么對于跨虛擬機的場景要如何處理呢?類比一下,本地鎖對應分布式鎖,那么鏈表(隊列)對應的就是分布式隊列了,正好Redis也有對應的數據結構來支撐這個功能。

Redisson

Redisson利用了redis本身的集合操作配合lua腳本來解決這個問題,這個過程和非公平鎖比起來要復雜的多。

這里會根據command分成兩組,一組是EVAL_NULL_BOOLEAN,tryAcquireOnce的語義,返回的是Boolean,另一組是EVAL_LONG,返回的是Long,即當前鎖的ttl,用來實現lockInterruptibly當獲取鎖失敗時用于等待下次競爭鎖的時間。

EVAL_NULL_BOOLEAN:

首先看第一段死循環,如注釋所寫,這段邏輯是清理已經過期的線程:

具體邏輯,首先判斷存儲線程的隊列/列表中是否有線程存在,當列表中的頭元素是空的話,說明沒有過期線程,這樣就可以break進行下面的鎖操作邏輯。

如果隊列不為空,就挨個檢測存儲的線程是否已經過期(過期的時間點是否已經是過去的某個時刻,即比當前時刻小),如果過期,那么將該線程從隊列中移除,同時將保存該線程過期時間點的數據也從對應的隊列中移除。

清理過程結束后,進行真正的鎖操作邏輯:

①如果當前鎖不存在,同時,存線程id的有序隊列不存在或者隊列存在且當前線程處于隊列頭(表明當前線程可以獲取到鎖)

②那么pop將當前threadId從隊列中移除,保證下次下一個線程可以搶鎖,zrem移除鎖超時隊列的threadId。

③threadId獲取到鎖,加鎖,并設置重入次數為1

④對該鎖設置超時時間

⑤返回nil(因為上面的指令是EVAL_NULL_BOOLEAN,所以這里返回的是true)

上面的①如果是false:

②看看當前線程是否已經獲取到鎖

③如果獲取到,那么用hincrby將重入次數計數加一

④重新設置過期時間

⑤返回nil(因為上面的指令是EVAL_NULL_BOOLEAN,所以這里返回的是true)

EVAL_LONG:

對于EVAL_LONG,唯一不同的地方在于,當獲取不到鎖的時候,因為有睡眠等待的語義,所以需要返回ttl,而不是直接tryAcquireOnce返回Boolean,所以lua腳本有所不同,具體在下圖描述的這一部分:

如果存儲線程的優先隊列中的第一個線程不是當前請求鎖的線程,那么ttl就是這優先隊列中第一個線程的ttl。否則,當前線程和優先隊列中第一個線程是同一個線程(可以獲取到鎖),那么ttl就是該鎖的ttl。

然后將該線程和該線程的ttl分別加入到對應的優先隊列中,zadd執行返回1,表示新增成功(如果是已存在的元素,表示更新操作,返回值不是1),說明該thread之前不在隊列中,此時通過rpush將其添加到存儲線程的優先隊列中去。

疑問:

這里有個問題還沒看明白,就是這里有個threadWaitTime,設置時間是5000ms,不知道是什么作用?

看完了lua腳本再補充說幾個要點:

①關于發布訂閱

我們看到FairLock重載了這兩個方法,和普通的鎖相比,加入了threadId屬性。這是為什么呢?因為這是公平鎖,redis中利用優先隊列保存了當前等待獲取鎖的所有線程,所以需要按照這些線程的優先順序來獲取鎖,所以要獲得下一個能獲得鎖的線程,只發布一個能讓該線程訂閱到的消息來執行操作。

總結

以上是生活随笔為你收集整理的Redisson(2-3)分布式锁实现对比 VS Java的ReentrantLock的FairLock的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。