新聞中心
Redisson 分布式鎖源碼之公平鎖排隊加鎖
作者:程序員小航 2021-07-01 09:42:08
前端
分布式
Redis Redis sorted set 有序集合數(shù)據(jù)結構:存放等待線程的順序,分數(shù) score 用來是等待線程的超時時間戳。

創(chuàng)新互聯(lián)建站成立10余年來,這條路我們正越走越好,積累了技術與客戶資源,形成了良好的口碑。為客戶提供成都做網站、成都網站設計、網站策劃、網頁設計、國際域名空間、網絡營銷、VI設計、網站改版、漏洞修補等服務。網站是否美觀、功能強大、用戶體驗好、性價比高、打開快等等,這些對于網站建設都非常重要,創(chuàng)新互聯(lián)建站通過對建站技術性的掌握、對創(chuàng)意設計的研究為客戶提供一站式互聯(lián)網解決方案,攜手廣大客戶,共同發(fā)展進步。
前言
在上一篇文章中已經分析過公平鎖的加鎖源碼,并得出結論:
Redis Hash 數(shù)據(jù)結構:存放當前鎖,Redis Key 就是鎖,Hash 的 field 是加鎖線程,Hash 的 value 是 重入次數(shù);
Redis List 數(shù)據(jù)結構:充當線程等待隊列,新的等待線程會使用 rpush 命令放在隊列右邊;
Redis sorted set 有序集合數(shù)據(jù)結構:存放等待線程的順序,分數(shù) score 用來是等待線程的超時時間戳。
現(xiàn)在看一下加鎖失敗被放到等待隊列之后,線程是如何處理的?
1排隊等鎖
源碼入口:org.redisson.RedissonLock#lock(long, java.util.concurrent.TimeUnit, boolean)。
線程進入排隊之后,在 Java 代碼中會 while (true) 一直循環(huán)調用 tryAcquire,嘗試獲取鎖。
最終還是來到 RedissonFairLock#tryLockInnerAsync 方法中。
方便起見,重新貼一下 Lua 腳本,以及腳本的參數(shù)含義。
- KEYS[1]:加鎖的名字,anyLock;
- KEYS[2]:加鎖等待隊列,redisson_lock_queue:{anyLock};
- KEYS[3]:等待隊列中線程鎖時間的 set 集合,redisson_lock_timeout:{anyLock},是按照鎖的時間戳存放到集合中的;
- ARGV[1]:鎖超時時間 30000
- ARGV[2]:UUID:ThreadId 組合 a3da2c83-b084-425c-a70f-5d9a08b37f31:1
- ARGV[3]:threadWaitTime 默認 300000
- ARGV[4]:currentTime 當前時間戳
源碼分析
第一部分,while 循環(huán):
- 從等待隊列 redisson_lock_queue:{anyLock} 中獲取第一個等待線程;
- 從等待線程超時集合 redisson_lock_timeout:{anyLock} 中獲取第一個等待線程的分數(shù);
- 沒有超時,直接結束,超時了,則直接移除。
第二部分,當前鎖存在,直接跳過。
第三部分,當前鎖不是持鎖線程,直接跳過。
第四部分,
直接返回當前鎖還有多久到期。
當前 Redisson 版本為 3.15.6,不同版本的略有不同。
隊列重排
這里不存在重新排序,因為官方認為這是一個 bug,重新進行了修復。
具體可以閱讀:Justin Corpron 2019/5/10, 04:13 Fix timeout drift in RedissonFairLock
最大的變化就是增加了第四部分。
圖僅僅代表兩個版本的差別,并不是代表這個版本才修改。
2總結
當線程獲取鎖失敗,進入到等待隊列時,ttl != null,在 Java 代碼中會不斷嘗試獲取鎖。
當鎖不存在且當前線程是在等待隊列頭時,直接獲得鎖。這個排隊的過程就是公平鎖的提現(xiàn)。
本文轉載自微信公眾號「程序員小航」,可以通過以下二維碼關注。轉載本文請聯(lián)系程序員小航公眾號。
新聞標題:Redisson分布式鎖源碼之公平鎖排隊加鎖
文章地址:http://m.5511xx.com/article/cogejjs.html


咨詢
建站咨詢
