欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于Redis的分布式鎖及原子性問題(短視頻開發(fā))

 更新時(shí)間:2025年06月21日 09:00:29   作者:云豹科技-蘇凌霄  
短視頻開發(fā)中,Redis分布式鎖通過SETNX實(shí)現(xiàn)加鎖與解鎖,需設(shè)置超時(shí)時(shí)間避免死鎖,為防止誤刪,釋放鎖時(shí)需判斷線程身份,并用Lua腳本保證原子性,確保安全操作,本文給大家介紹基于Redis的分布式鎖及原子性問題,感興趣的朋友一起看看吧

短視頻開發(fā),基于Redis的分布式鎖及原子性問題

用 Redis 實(shí)現(xiàn)分布式鎖

主要應(yīng)用到的是 SETNX key value命令(如果不存在,則設(shè)置)

主要要實(shí)現(xiàn)兩個(gè)功能:

1、獲取鎖(設(shè)置一個(gè) key)
2、釋放鎖 (刪除 key)
基本思想是執(zhí)行了 SETNX命令的線程獲得鎖,在完成操作后,需要?jiǎng)h除 key,釋放鎖。

加鎖:

@Override
public boolean tryLock(long timeoutSec) {
    // 獲取線程標(biāo)示
    String threadId = ID_PREFIX + Thread.currentThread().getId();
    // 獲取鎖
    Boolean success = stringRedisTemplate.opsForValue()
            .setIfAbsent(KEY_PREFIX + name, threadId, timeoutSec, TimeUnit.SECONDS);
    return Boolean.TRUE.equals(success);
}

釋放鎖:

@Override
public void unlock() {
    // 獲取線程標(biāo)示
    String threadId = ID_PREFIX + Thread.currentThread().getId();
    // 獲取鎖中的標(biāo)示
    String id = stringRedisTemplate.opsForValue().get(KEY_PREFIX + name);
    // 釋放鎖
    stringRedisTemplate.delete(KEY_PREFIX + name);
}

可是這里會(huì)存在一個(gè)隱患——假設(shè)該線程發(fā)生阻塞(或者其他問題),一直不釋放鎖(刪除 key)這可怎么辦?

為了解決這個(gè)問題,我們需要為 key 設(shè)計(jì)一個(gè)超時(shí)時(shí)間,讓它超時(shí)失效;但是這個(gè)超時(shí)時(shí)間的長短卻不好確定:

1、設(shè)置過短,會(huì)導(dǎo)致其他線程提前獲得鎖,引發(fā)線程安全問題。
2、設(shè)置過長,線程需要額外等待。

鎖的誤刪

 超時(shí)時(shí)間是一個(gè)非常不好把握的東西,因?yàn)闃I(yè)務(wù)線程的阻塞時(shí)間是不可預(yù)估的,在極端情況下,它總能阻塞到 lock 超時(shí)失效,正如上圖中的線程1,鎖超時(shí)釋放了,導(dǎo)致線程2也進(jìn)來了,這時(shí)候 lock 是 線程2的鎖了(key 相同,value不同,value一般是線程唯一標(biāo)識(shí));假設(shè)這時(shí)候,線程1突然不阻塞了,它要釋放鎖,如果按照剛剛的代碼邏輯的話,它會(huì)釋放掉線程2的鎖;線程2的鎖被釋放掉之后,又會(huì)導(dǎo)致其他線程進(jìn)來(線程3),如此往復(fù)。。。

為了解決這個(gè)問題,需要在釋放鎖時(shí)多加一個(gè)判斷,每個(gè)線程只釋放自己的鎖,不能釋放別人的鎖!

釋放鎖

@Override
public void unlock() {
    // 獲取線程標(biāo)示
    String threadId = ID_PREFIX + Thread.currentThread().getId();
    // 獲取鎖中的標(biāo)示
    String id = stringRedisTemplate.opsForValue().get(KEY_PREFIX + name);
    // 判斷標(biāo)示是否一致
    if(threadId.equals(id)) {
        // 釋放鎖
        stringRedisTemplate.delete(KEY_PREFIX + name);
    }
}

原子性問題

剛剛我們談?wù)摰尼尫沛i的邏輯:

1、判斷當(dāng)前鎖是當(dāng)前線程的鎖
2、當(dāng)前線程釋放鎖
可以看到釋放鎖是分兩步完成的,如果你是對(duì)并發(fā)比較有感覺的話,應(yīng)該一下子就知道這里會(huì)存在問題了。

分步執(zhí)行,并發(fā)問題!

假設(shè) 線程1 已經(jīng)判斷當(dāng)前鎖是它的鎖了,正準(zhǔn)備釋放鎖,可偏偏這時(shí)候它阻塞了(可能是 FULL GC 引起的),鎖超時(shí)失效,線程2來加鎖,這時(shí)候鎖是線程2的了;可是如果線程1這時(shí)候醒過來,因?yàn)樗呀?jīng)執(zhí)行了步驟1了的,所以這時(shí)候它會(huì)直接直接步驟2,釋放鎖(可是此時(shí)的鎖不是線程1的了)

其實(shí)這就是一個(gè)原子性的問題,剛剛釋放鎖的兩步應(yīng)該是原子的,不可分的!

要使得其滿足原子性,則需要在 Redis 中使用 Lua 腳本了。

引入 Lua 腳本保持原子性
lua 腳本:

-- 比較線程標(biāo)示與鎖中的標(biāo)示是否一致
if(redis.call('get', KEYS[1]) ==  ARGV[1]) then
    -- 釋放鎖 del key
    return redis.call('del', KEYS[1])
end
return 0

Java 中調(diào)用執(zhí)行:

public class SimpleRedisLock implements ILock {
?
    private String name;
    private StringRedisTemplate stringRedisTemplate;
?
    public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {
        this.name = name;
        this.stringRedisTemplate = stringRedisTemplate;
    }
?
    private static final String KEY_PREFIX = "lock:";
    private static final String ID_PREFIX = UUID.randomUUID().toString(true) + "-";
    private static final DefaultRedisScript<Long> UNLOCK_SCRIPT;
    static {
        UNLOCK_SCRIPT = new DefaultRedisScript<>();
        UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));
        UNLOCK_SCRIPT.setResultType(Long.class);
    }
?
    @Override
    public boolean tryLock(long timeoutSec) {
        // 獲取線程標(biāo)示
        String threadId = ID_PREFIX + Thread.currentThread().getId();
        // 獲取鎖
        Boolean success = stringRedisTemplate.opsForValue()
                .setIfAbsent(KEY_PREFIX + name, threadId, timeoutSec, TimeUnit.SECONDS);
        return Boolean.TRUE.equals(success);
    }
?
    @Override
    public void unlock() {
        // 調(diào)用lua腳本
        stringRedisTemplate.execute(
                UNLOCK_SCRIPT,
                Collections.singletonList(KEY_PREFIX + name),
                ID_PREFIX + Thread.currentThread().getId());
    }
}

到了目前為止,我們?cè)O(shè)計(jì)的 Redis 分布式鎖已經(jīng)是生產(chǎn)可用的,相對(duì)完善的分布式鎖了。

以上就是短視頻開發(fā),基于Redis的分布式鎖及原子性問題, 更多內(nèi)容歡迎關(guān)注之后的文章

到此這篇關(guān)于短視頻開發(fā),基于Redis的分布式鎖及原子性問題的文章就介紹到這了,更多相關(guān)Redis的分布式鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • linux 常見的標(biāo)識(shí)與Redis數(shù)據(jù)庫詳解

    linux 常見的標(biāo)識(shí)與Redis數(shù)據(jù)庫詳解

    這篇文章主要介紹了linux 常見的標(biāo)識(shí)與Redis數(shù)據(jù)庫,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10
  • redis 主從備份及其主備切換的操作

    redis 主從備份及其主備切換的操作

    這篇文章主要介紹了redis 主從備份及其主備切換的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • 淺談Redis中的緩存更新策略

    淺談Redis中的緩存更新策略

    這篇文章主要介紹了淺談Redis中的緩存更新策略,CacheAsidePatter是我們比較常用的緩存更新策略,其由緩存調(diào)用者在更新數(shù)據(jù)庫時(shí),在業(yè)務(wù)邏輯中設(shè)置緩存更新,需要的朋友可以參考下
    2023-08-08
  • Redis分布式緩存-Redis持久化詳解

    Redis分布式緩存-Redis持久化詳解

    RDB持久化將內(nèi)存數(shù)據(jù)快照到磁盤,用于故障恢復(fù);AOF持久化記錄每個(gè)寫命令,提供數(shù)據(jù)安全性,兩者各有優(yōu)缺點(diǎn),可根據(jù)需求選擇或結(jié)合使用
    2024-12-12
  • 深入理解redis分布式鎖和消息隊(duì)列

    深入理解redis分布式鎖和消息隊(duì)列

    本篇文章主要介紹了深入理解redis分布式鎖和消息隊(duì)列,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-07-07
  • Redis中的List結(jié)構(gòu)從使用到原理分析

    Redis中的List結(jié)構(gòu)從使用到原理分析

    本文詳解Redis List結(jié)構(gòu),涵蓋其基本操作、內(nèi)部實(shí)現(xiàn)(ziplist、linkedlist、quicklist)、應(yīng)用場(chǎng)景(消息隊(duì)列、動(dòng)態(tài)排行、歷史記錄)及性能優(yōu)化策略,如配置參數(shù)、批量操作,幫助開發(fā)者高效使用
    2025-09-09
  • Redis分布式鎖升級(jí)版RedLock及SpringBoot實(shí)現(xiàn)方法

    Redis分布式鎖升級(jí)版RedLock及SpringBoot實(shí)現(xiàn)方法

    這篇文章主要介紹了Redis分布式鎖升級(jí)版RedLock及SpringBoot實(shí)現(xiàn),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-02-02
  • Redis出現(xiàn)(error)NOAUTH?Authentication?required.報(bào)錯(cuò)的解決辦法(秒懂!)

    Redis出現(xiàn)(error)NOAUTH?Authentication?required.報(bào)錯(cuò)的解決辦法(秒懂!)

    這篇文章主要給大家介紹了關(guān)于Redis出現(xiàn)(error)NOAUTH?Authentication?required.報(bào)錯(cuò)的解決辦法,對(duì)于 這個(gè)錯(cuò)誤這通常是因?yàn)镽edis服務(wù)器需要密碼進(jìn)行身份驗(yàn)證,但客戶端沒有提供正確的身份驗(yàn)證信息導(dǎo)致的,需要的朋友可以參考下
    2024-03-03
  • Redis源碼解析sds字符串實(shí)現(xiàn)示例

    Redis源碼解析sds字符串實(shí)現(xiàn)示例

    這篇文章主要為大家介紹了Redis源碼解析sds字符串實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • redis的bigkey掃描腳本深入介紹

    redis的bigkey掃描腳本深入介紹

    這篇文章主要給大家介紹了關(guān)于redis的bigkey掃描腳本的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-07-07

最新評(píng)論