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

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

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

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

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

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

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

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

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

直接看代碼例子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è)務(wù)處理耗時
                // TimeUnit.SECONDS.sleep(3);
                // 模擬業(yè)務(wù)處理耗時 大于鎖過期,可能導(dǎo)致非自己持有的鎖被釋放。
                TimeUnit.SECONDS.sleep(20);
            } else {
                System.out.println(Thread.currentThread().getName() + "未能獲取到鎖,已放棄嘗試");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 判斷當(dāng)前線程是否持有鎖
            if (success && lock.isHeldByCurrentThread()) {
                //釋放當(dāng)前鎖
                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è)務(wù)處理耗時
            // TimeUnit.SECONDS.sleep(3);
            // 模擬業(yè)務(wù)處理耗時 大于鎖過期,可能導(dǎo)致非自己持有的鎖被釋放。
            TimeUnit.SECONDS.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 判斷當(dāng)前線程是否持有鎖
            if (success && lock.isHeldByCurrentThread()) {
                //釋放當(dāng)前鎖
                lock.unlock();
                System.out.println(Thread.currentThread().getName() + "釋放鎖"+ LocalDateTime.now());
            }
        }
        return "";
    }

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

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

可以結(jié)合文章一起看 看懂Redisson分布式鎖源碼,其實(shí)并不難

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

lock() 和 tryLock()都會用的 tryAcquireAsync(),看到區(qū)別,其實(shí)核心是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ù),默認(rèn)leaseTime = -1
            lock.lock();

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

 當(dāng)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); // 設(shè)置鎖的看門狗超時時間為10秒

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

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

1.拿鎖LUA。

ChaGPT解釋此段LUA:

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

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

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

需要注意的是,因?yàn)?nbsp;tryLockInnerAsync 方法的實(shí)現(xiàn)是原子的,所以它可以保證在分布式環(huán)境下的正確性。同時,它也支持重入鎖的功能,因?yàn)樗A袅随i的持有者和持有計(jì)數(shù)器的值。

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

ChaGPT解釋此段LUA:

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

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

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

 3.解鎖LUA

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

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

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

 4.預(yù)留了一個強(qiáng)制暴力解鎖的方法給用戶

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

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

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

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

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

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

相關(guān)文章

  • Redis的常見四種部署方案

    Redis的常見四種部署方案

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

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

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

    遠(yuǎn)程連接阿里云服務(wù)器上的redis報(bào)錯的問題解決

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

    一文詳解redis高可用Sentinel?

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

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

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

    Redis 的各項(xiàng)功能主要解決了什么問題

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

    Redis報(bào)錯“NOAUTH Authentication required”兩種解決方案

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

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

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

    redis分布式Jedis類型轉(zhuǎn)換的異常深入研究

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

    Redis 執(zhí)行性能測試

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

最新評論

左贡县| 万宁市| 临江市| 奉化市| 湟源县| 景泰县| 朝阳区| 台东市| 新郑市| 邯郸县| 龙里县| 枝江市| 汪清县| 清丰县| 清徐县| 莒南县| 玉山县| 晋中市| 吉木乃县| 高雄县| 耒阳市| 金昌市| 唐河县| 墨江| 柳江县| 若羌县| 忻城县| 杭锦后旗| 屏边| 简阳市| 南岸区| 博湖县| 卢湾区| 涞源县| 普定县| 铅山县| 平潭县| 滕州市| 五常市| 武冈市| 洞头县|