最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Redission實現(xiàn)分布式鎖lock()和tryLock()方法的區(qū)別小結

 更新時間:2024年07月31日 09:44:18   作者:bulingbuling^_^  
Redisson是一種基于Redis的分布式鎖框架,提供了lock()和tryLock()兩種獲取鎖的方法,本文主要介紹了Redission實現(xiàn)分布式鎖lock()和tryLock()方法的區(qū)別小結,具有一定的參考價值,感興趣的可以了解一下

本文主要介紹了 Redission實現(xiàn)分布式鎖lock()和tryLock()方法的區(qū)別小結,具體如下:

 lock.lock(30, TimeUnit.SECONDS); // 嘗試獲取鎖30秒,如果獲取不到則放棄
//嘗試獲取鎖,等待5秒,持有鎖10秒鐘
boolean success = lock.tryLock(5, 10, TimeUnit.SECONDS);

Redisson 是一種基于 Redis 的分布式鎖框架,提供了 lock() 和 tryLock() 兩種獲取鎖的方法。

lock() 方法是阻塞獲取鎖的方式,如果當前鎖被其他線程持有,則當前線程會一直阻塞等待獲取鎖,直到獲取到鎖或者發(fā)生超時或中斷等情況才會結束等待。該方法獲取到鎖之后可以保證線程對共享資源的訪問是互斥的,適用于需要確保共享資源只能被一個線程訪問的場景。Redisson 的 lock() 方法支持可重入鎖和公平鎖等特性,可以更好地滿足多線程并發(fā)訪問的需求。

而 tryLock() 方法是一種非阻塞獲取鎖的方式,在嘗試獲取鎖時不會阻塞當前線程,而是立即返回獲取鎖的結果,如果獲取成功則返回 true,否則返回 false。Redisson 的 tryLock() 方法支持加鎖時間限制、等待時間限制以及可重入等特性,可以更好地控制獲取鎖的過程和等待時間,避免程序出現(xiàn)長時間無法響應等問題。

因此,兩種獲取鎖的方式各有優(yōu)缺點,在實際應用中需要根據(jù)具體場景和業(yè)務需求來選擇合適的方法,以確保程序的正確性和高效性。

直接看代碼例子lock.tryLock等待時間和持有時間都為0時。

    public String RedissonLock1() {
        RLock lock = redissonClient.getLock("order_lock");
        boolean success = true;
        try {
            System.out.println("獲取鎖前的時間:"+LocalDateTime.now());
            // 嘗試獲取鎖,等待0秒,持有鎖0秒鐘
            success = lock.tryLock(0, 0, TimeUnit.SECONDS);
            // lock.lock(0, TimeUnit.SECONDS);
            System.out.println("獲取鎖后的時間:"+LocalDateTime.now());
            if (success) {
                System.out.println(Thread.currentThread().getName() + "獲取到鎖"+ LocalDateTime.now());
                // 模擬業(yè)務處理耗時
                // TimeUnit.SECONDS.sleep(3);
                // 模擬業(yè)務處理耗時 大于鎖過期,可能導致非自己持有的鎖被釋放。
                TimeUnit.SECONDS.sleep(20);
            } else {
                System.out.println(Thread.currentThread().getName() + "未能獲取到鎖,已放棄嘗試");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 判斷當前線程是否持有鎖
            if (success && lock.isHeldByCurrentThread()) {
                //釋放當前鎖
                lock.unlock();
                System.out.println(Thread.currentThread().getName() + "釋放鎖"+ LocalDateTime.now());
            }
        }
        return "";
    }

可以看到立即拿鎖,拿不到立即就返回

 lock()方法的持有鎖時間為0時

    public String RedissonLock2() {
        RLock lock = redissonClient.getLock("order_lock");
        boolean success = true;
        try {
            System.out.println("獲取鎖前的時間:"+LocalDateTime.now());
            // 嘗試獲取鎖,等待5秒,持有鎖10秒鐘
           // success = lock.tryLock(0, 0, TimeUnit.SECONDS);
            lock.lock(0, TimeUnit.SECONDS);
            System.out.println("獲取鎖后的時間:"+LocalDateTime.now());
            // 模擬業(yè)務處理耗時
            // TimeUnit.SECONDS.sleep(3);
            // 模擬業(yè)務處理耗時 大于鎖過期,可能導致非自己持有的鎖被釋放。
            TimeUnit.SECONDS.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 判斷當前線程是否持有鎖
            if (success && lock.isHeldByCurrentThread()) {
                //釋放當前鎖
                lock.unlock();
                System.out.println(Thread.currentThread().getName() + "釋放鎖"+ LocalDateTime.now());
            }
        }
        return "";
    }

 可以看到第二次獲取鎖時是阻塞的,等著業(yè)務處理了20s后,才獲取到鎖。

lock() 方法是阻塞獲取鎖的方式,而 tryLock() 方法是一種非阻塞獲取鎖的方式。

可以結合文章一起看 看懂Redisson分布式鎖源碼,其實并不難

看門狗續(xù)約時間默認是30秒

lock() 和 tryLock()都會用的 tryAcquireAsync(),看到區(qū)別,其實核心是leaseTime是否 > 0 

所以是否使用看門狗不算是tryLock和lock()的區(qū)別,可以看下面這5種情況。

            //走if (leaseTime > 0)邏輯
            lock.tryLock(5, 10, TimeUnit.SECONDS);
            lock.lock(10, TimeUnit.SECONDS);

            //不走if (leaseTime > 0)邏輯
            lock.tryLock(0, -1, TimeUnit.SECONDS);
            lock.lock(-1, TimeUnit.SECONDS);
            //lock()不帶參數(shù),默認leaseTime = -1
            lock.lock();

leaseTime不大于0時,會執(zhí)行scheduleExpirationRenewal(threadId);

 當oldEntry == null時,執(zhí)行renewExpiration(); 就是個定時器,即是看門狗核心邏輯了。

    private void renewExpiration() {
        ExpirationEntry ee = EXPIRATION_RENEWAL_MAP.get(getEntryName());
        if (ee == null) {
            return;
        }
        
        Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
            @Override
            public void run(Timeout timeout) throws Exception {
                ExpirationEntry ent = EXPIRATION_RENEWAL_MAP.get(getEntryName());
                if (ent == null) {
                    return;
                }
                Long threadId = ent.getFirstThreadId();
                if (threadId == null) {
                    return;
                }
                
                CompletionStage<Boolean> future = renewExpirationAsync(threadId);
                future.whenComplete((res, e) -> {
                    if (e != null) {
                        log.error("Can't update lock {} expiration", getRawName(), e);
                        EXPIRATION_RENEWAL_MAP.remove(getEntryName());
                        return;
                    }
                    
                    if (res) {
                        // reschedule itself
                        renewExpiration();
                    } else {
                        cancelExpirationRenewal(null);
                    }
                });
            }
        }, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS);
        
        ee.setTimeout(task);
    }

 其中有下面紅圈這段邏輯,也就是看門狗之所以在三分之一的時候執(zhí)行的原因, 沒有自定義時

config.setLockWatchdogTimeout(10000); // 設置鎖的看門狗超時時間為10秒

默認就是30秒 除以3  也就是10秒時執(zhí)行。

 再看幾段實現(xiàn)分布式鎖核心的LUA腳本

1.拿鎖LUA。

ChaGPT解釋此段LUA:

這是 Redisson 中 RedissonLock 類實現(xiàn)的 tryLockInnerAsync() 方法。該方法用于嘗試獲取鎖,它會先檢查鎖是否已經(jīng)被其他線程持有,如果沒有被持有,則將當前線程設置為鎖的持有者,并返回 null;否則返回當前線程需要等待的時間,以便稍后再次嘗試獲取鎖。

具體地說,Lua 腳本的邏輯是這樣的:

  • 如果鎖不存在或者鎖已經(jīng)被當前線程持有(使用 hash 存儲鎖的持有者),則將當前線程作為鎖的持有者,并且設置鎖的過期時間,并返回 null。這里的代碼具體操作包括使用 HEXISTS 命令檢查鎖的持有情況,使用 HINCRBY 命令來設置持有者和持有計數(shù)器并提高計數(shù)器的值,以及使用 PEXPIRE 命令來設置鎖的過期時間。
  • 如果鎖已經(jīng)被其他線程持有,則返回當前線程需要等待的時間,以便稍后再次嘗試獲取鎖。這里使用 PTTL 命令來查詢鎖的過期時間,并返回給調用方。

需要注意的是,因為 tryLockInnerAsync 方法的實現(xiàn)是原子的,所以它可以保證在分布式環(huán)境下的正確性。同時,它也支持重入鎖的功能,因為它保留了鎖的持有者和持有計數(shù)器的值。

 2.看門狗續(xù)租LUA

ChaGPT解釋此段LUA:

這是 Redisson 中 RedissonLock 類實現(xiàn)的 renewExpirationAsync(long threadId) 方法。該方法用于續(xù)期鎖的過期時間,以避免鎖在使用期間失效。首先,該方法會檢查當前線程是否持有鎖(通過 hash 存儲鎖的持有者),如果當前線程不是鎖的持有者,則會直接返回 false 表示續(xù)期失敗。如果當前線程是鎖的持有者,則會將鎖的過期時間重置為 internalLockLeaseTime 毫秒,并返回 true 表示續(xù)期成功。

具體來說,Lua 腳本的邏輯是這樣的:

  • 如果當前線程不是鎖的持有者,則直接返回 0(false)。
  • 如果當前線程是鎖的持有者,則將鎖的過期時間重置為 internalLockLeaseTime 毫秒,并返回 1(true)。

 3.解鎖LUA

這是 Redisson 中 RedissonLock 類實現(xiàn)的 unlockInnerAsync(long threadId) 方法。該方法用于釋放鎖,首先它會檢查當前線程是否持有鎖(通過 hash 存儲鎖的持有者),如果當前線程不是鎖的持有者,則直接返回 null;如果當前線程是鎖的持有者,則將鎖的計數(shù)器減一,如果減完之后計數(shù)器大于 0,則續(xù)期鎖的過期時間,并返回 false 表示未成功釋放鎖;否則則刪除該鎖,并發(fā)布一個消息通知其他競爭者可以獲取到該鎖了,最后返回 true 表示成功釋放鎖。

具體來說,Lua 腳本的邏輯是這樣的:

  • 如果當前線程不是鎖的持有者,則直接返回 null。
  • 如果當前線程是鎖的持有者,則使用 HINCRBY 命令將鎖的計數(shù)器減一,并獲取計數(shù)器的當前值。
  • 如果鎖的計數(shù)器大于 0,則使用 PEXPIRE 命令續(xù)期鎖的過期時間,并返回 0(false)。
  • 如果鎖的計數(shù)器已經(jīng)為 0,則使用 DEL 命令刪除該鎖,并使用 PUBLISH 命令發(fā)布一個消息通知其他競爭者可以獲取到該鎖了,最后返回 1(true)。

 4.預留了一個強制暴力解鎖的方法給用戶

//沒有釋放鎖,導致整個系統(tǒng)的性能下降甚至故障,必須強行停止這個鎖時 使用lock.forceUnlock();

這是 Redisson 中 RedissonLock 類實現(xiàn)的 forceUnlockAsync() 方法。該方法用于強制釋放鎖,取消鎖定的狀態(tài)。在方法內(nèi)部,它會調用 cancelExpirationRenewal(null) 方法來停止看門狗線程的續(xù)期任務。然后使用 evalWriteAsync 方法執(zhí)行 Lua 腳本,通過將鎖的名字和訂閱通道作為參數(shù)傳入,刪除鎖并返回結果,同時發(fā)布一條消息到訂閱通道上,表示這個鎖被釋放了。

具體地說,Lua 腳本的邏輯是這樣的:

  • 使用 DEL 命令刪除鎖,如果返回值為 1,則說明鎖被成功刪除,否則說明當前線程并沒有持有這個鎖,直接返回 0。
  • 如果鎖被成功刪除,使用 PUBLISH 命令發(fā)布一條消息到訂閱通道上,表示這個鎖被釋放了,并返回 1。

 在所有操作鎖的地方使用LUA腳本,單線程,天然線程安全。

到此這篇關于Redission實現(xiàn)分布式鎖lock()和tryLock()方法的區(qū)別小結的文章就介紹到這了,更多相關Redission lock()和tryLock() 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Redis的常見四種部署方案

    Redis的常見四種部署方案

    這篇文章介紹Reids最為常見的四種部署模式,其實Reids和數(shù)據(jù)庫的集群模式差不多,可以分為 Redis單機模式部署、Redis主從模式部署、Redis哨兵模式部署、Cluster集群模式部署,其他的部署方式基本都是圍繞以下幾種方式在進行調整到適應的生產(chǎn)環(huán)境,感興趣的朋友一起看看吧
    2023-11-11
  • 使用redis實現(xiàn)令牌桶算法和漏桶算法方式

    使用redis實現(xiàn)令牌桶算法和漏桶算法方式

    這篇文章主要介紹了使用redis實現(xiàn)令牌桶算法和漏桶算法方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-07-07
  • 遠程連接阿里云服務器上的redis報錯的問題解決

    遠程連接阿里云服務器上的redis報錯的問題解決

    本文主要介紹了遠程連接阿里云服務器上的redis報錯的問題,出現(xiàn)?Redis Client On Error: Error: connect ECONNREFUSED 47.100.XXX.XX:6379?錯誤,下面就來介紹一下解決方法,感興趣的可以了解一下
    2025-04-04
  • 一文詳解redis高可用Sentinel?

    一文詳解redis高可用Sentinel?

    本文主要介紹了redis高可用Sentinel的使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-05-05
  • 詳解如何利用Redis實現(xiàn)生成唯一ID

    詳解如何利用Redis實現(xiàn)生成唯一ID

    隨著下單流量逐漸上升,為了降低數(shù)據(jù)庫的訪問壓力,需要通過請求唯一ID+redis分布式鎖來防止接口重復提交。今天我們就一起來看探討一下,如何通過服務端來完成請求唯一?ID?的生成
    2022-11-11
  • Redis 的各項功能主要解決了什么問題

    Redis 的各項功能主要解決了什么問題

    Redis是一個基于BSD開源的項目,是一個把結構化的數(shù)據(jù)放在內(nèi)存中的一個存儲系統(tǒng),你可以把它作為數(shù)據(jù)庫,緩存和消息中間件來使用。這篇文章主要介紹了Redis 的各項功能主要解決了什么問題,需要的朋友可以參考下
    2018-10-10
  • Redis報錯“NOAUTH Authentication required”兩種解決方案

    Redis報錯“NOAUTH Authentication required”兩種解決方案

    Redis提供了一個命令行工具redis-cli,它允許你直接連接到Redis服務器,如果你知道Redis服務器的密碼,你可以在連接時直接提供它,本文給大家介紹連接了Redis報錯“NOAUTH Authentication required”兩種解決方案
    2024-05-05
  • 使用Spring?Boot實現(xiàn)Redis鍵過期回調功能示例詳解

    使用Spring?Boot實現(xiàn)Redis鍵過期回調功能示例詳解

    這篇文章主要介紹了使用Spring?Boot實現(xiàn)Redis鍵過期回調功能,就是一個實現(xiàn)Redis鍵過期回調功能的Spring?Boot應用的示例,代碼簡單易懂,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-07-07
  • redis分布式Jedis類型轉換的異常深入研究

    redis分布式Jedis類型轉換的異常深入研究

    這篇文章主要介紹了redis分布式Jedis類型轉換的異常深入研究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-03-03
  • Redis 執(zhí)行性能測試

    Redis 執(zhí)行性能測試

    這篇文章主要介紹了Redis 執(zhí)行性能測試的方法,文中講解非常細致,幫助大家更好的理解和學習redis,感興趣的朋友可以了解下
    2020-08-08

最新評論

兰考县| 华安县| 扬州市| 金塔县| 平顶山市| 辽中县| 遵义县| 石门县| 临江市| 凌海市| 岢岚县| 河北区| 临澧县| 九江县| 崇明县| 平度市| 辛集市| 清远市| 榆树市| 红安县| 图木舒克市| 龙川县| 资阳市| 城口县| 松溪县| 岢岚县| 斗六市| 民勤县| 井冈山市| 邵武市| 湘西| 天台县| 博野县| 个旧市| 农安县| 郴州市| 义乌市| 兴城市| 永靖县| 鲁山县| 大理市|