Redission分布式鎖實(shí)現(xiàn)原理

一、概述

redission分布式鎖的特點(diǎn)有可重入、自動續(xù)費(fèi)等,本文通過方法RedissonLock#lock()一步步介紹redission分布式鎖如何獲取鎖、鎖自動續(xù)費(fèi)及鎖釋放

二、獲取鎖

  1. lock()獲取鎖有兩種方式,可以指定鎖的最大時長,不指定會默認(rèn)最大時長為-1
    方法定位:org.redisson.RedissonLock#lock()

    image.png

  2. 設(shè)置鎖的時候,如果設(shè)置了最大有效時長會獲取鎖后直接返回,而沒有設(shè)置最大有效時長的會把時間設(shè)為看門狗配置的時間,默認(rèn)30s,并且獲取鎖成功后會啟動看門狗,
    方法定位:org.redisson.RedissonLock#tryAcquireOnceAsync

    image.png

  3. 通過LUA腳本爭搶鎖
    代碼定位:org.redisson.RedissonLock#tryLockInnerAsync

    image.png

if (redis.call('exists', KEYS[1]) == 0) then  -- 判斷鎖是否存在
redis.call('hincrby', KEYS[1], ARGV[2], 1); -- 保持鎖的信息,數(shù)據(jù)結(jié)構(gòu)為map,并且value是自增的,value表示重入鎖的次數(shù)
redis.call('pexpire', KEYS[1], ARGV[1]); -- 設(shè)置鎖的有效期
return nil; 
end;  -- 返回結(jié)束

if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then -- 當(dāng)鎖存在時,判斷通過map的key是否存在,存在則是重入鎖
redis.call('hincrby', KEYS[1], ARGV[2], 1); -- 重入鎖 value自增1,代表重入鎖+1
redis.call('pexpire', KEYS[1], ARGV[1]); -- 設(shè)置鎖的有效期
return nil;
end;  -- 返回結(jié)束

return redis.call('pttl', KEYS[1]); -- 如果所存在并且不是重入鎖,就直接返回鎖的有效時間
  • KEYS[1]:表示自定義鎖的key, 例如:RLock myLock = redissonClient.getLock("myLock");, KEYS[1] 就是 myLock
  • ARGV[1]:表示鎖的有效期,單位是毫秒
  • ARGV[2]:獲取鎖線程的唯一標(biāo)識,后取用來判斷是否重入鎖
  1. 獲取鎖不成功會循環(huán)獲取,直到成功或中斷結(jié)束


    image.png
  2. 看門狗啟動,延時任務(wù)遞歸實(shí)現(xiàn)自動續(xù)費(fèi)
    方法定位:org.redisson.RedissonLock#renewExpiration

    image.png

  3. 看門狗通過Lua腳本續(xù)費(fèi)
    代碼定位:org.redisson.RedissonLock#renewExpirationAsync

    image.png

  • KEYS[1]:表示自定義鎖的key, 例如:RLock myLock = redissonClient.getLock("myLock");, KEYS[1] 就是 myLock
  • ARGV[1]:表示鎖的有效期,單位是毫秒
  • ARGV[2]:獲取鎖線程的唯一標(biāo)識,后取用來判斷是否重入鎖
if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then -- 判斷鎖是否存在
redis.call('pexpire', KEYS[1], ARGV[1]); -- 重置鎖的有效時間續(xù)費(fèi)
return 1; -- 續(xù)費(fèi)成功返回1
end;
return 0; -- 續(xù)費(fèi)失敗返回0

二、釋放鎖

  1. 通過Lua腳本釋放鎖
    代碼定位:org.redisson.RedissonLock#unlockInnerAsync
    image.png
if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then -- 通過本線程的唯一標(biāo)識判斷本線程的鎖是否存在
return nil; -- 不存在本線程的鎖, 直接返回
end;
local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); -- 可能重入了多個鎖,先執(zhí)行value-1,去掉一個鎖
if (counter > 0) then -- 如果大于0, 表示重入鎖還沒有釋放完
redis.call('pexpire', KEYS[1], ARGV[2]); -- 重置鎖的有效期續(xù)費(fèi)
return 0;  -- 返回0標(biāo)識
else
redis.call('del', KEYS[1]); -- 鎖已經(jīng)釋放完了,把鎖刪除
redis.call('publish', KEYS[2], ARGV[1]); -- 發(fā)布消息鎖已經(jīng)釋放
return 1; -- 返回1標(biāo)識
end;
return nil;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容