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

Java實(shí)現(xiàn)Redis分布式鎖的三種方案匯總

 更新時(shí)間:2023年11月05日 08:03:21   作者:xcya  
setnx、Redisson、RedLock?都可以實(shí)現(xiàn)分布式鎖,從易到難得排序?yàn)椋簊etnx?<?Redisson?<?RedLock,本文為大家整理了三種方法的實(shí)現(xiàn),希望對(duì)大家有所幫助

序言

setnx、Redisson、RedLock 都可以實(shí)現(xiàn)分布式鎖,從易到難得排序?yàn)椋簊etnx < Redisson < RedLock。一般情況下,直接使用 Redisson 就可以啦,有很多邏輯框架的作者都已經(jīng)考慮到了。

方案一:setnx

1.1、簡(jiǎn)單實(shí)現(xiàn)

下面的鎖實(shí)現(xiàn)可以用在測(cè)試或者簡(jiǎn)單場(chǎng)景,但是它存在以下問(wèn)題,使其不適合用在正式環(huán)境。

  • 鎖可能被誤刪: 在解鎖操作中,如果一個(gè)線程的鎖已經(jīng)因?yàn)槌瑫r(shí)而被自動(dòng)釋放,然后又被其他線程獲取到,這時(shí)原線程再來(lái)解鎖就會(huì)誤刪其他線程的鎖。
  • 臨界區(qū)代碼不安全: 線程 A 還沒(méi)有執(zhí)行完臨界區(qū)代碼,鎖就過(guò)期釋放掉了。線程 B 此時(shí)又能獲取到鎖,進(jìn)入臨界區(qū)代碼,導(dǎo)致了臨界區(qū)代碼非串行執(zhí)行,帶來(lái)了線程不安全的問(wèn)題。
public class RedisLock {
?
    @Autowired
    private StringRedisTemplate redisTemplate;
?
    /**
     * 加鎖
     */
    private boolean tryLock(String key) {
        Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);
        return BooleanUtil.isTrue(flag);
    }
?
    /**
     * 解鎖
     */
    private void unlock(String key) {
        redisTemplate.delete(key);
    }
}

1.2、使用 lua 腳本加鎖、解鎖

lua 腳本是原子的,不管寫(xiě)多少 lua 腳本代碼,redis 都是通過(guò)一條命令去執(zhí)行的。

下述代碼使用了 lua 腳本進(jìn)行加鎖/解鎖,保證了加鎖和解鎖的時(shí)候都是原子性的,是一種相對(duì)較好的 Redis 分布式鎖的實(shí)現(xiàn)方式。

它支持獲得鎖的線程才能釋放鎖,如果線程 1 因?yàn)殒i過(guò)期而丟掉了鎖,然后線程 2 拿到了鎖。此時(shí)線程 1 的業(yè)務(wù)代碼執(zhí)行完以后,也無(wú)法釋放掉線程 2 的鎖,解決了誤刪除的問(wèn)題。

public class RedisLock {
?
    private final StringRedisTemplate redisTemplate;
?
    public RedisDistributedLock(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
?
    public boolean tryLock(String lockKey, String lockValue, long expireTimeInSeconds) {
        try {
            //加鎖成功返回 true,加鎖失敗返回 fasle。效果等同于 redisTemplate.opsForValue().setIfAbsent
            String luaScript = "if redis.call('set', KEYS[1], ARGV[1], 'NX', 'EX', ARGV[2]) then return 1 else return 0 end";
            RedisScript<Long> redisScript = new DefaultRedisScript<>(luaScript, Long.class);
            Long result = redisTemplate.execute(redisScript, Collections.singletonList(lockKey), lockValue, String.valueOf(expireTimeInSeconds));
?
            return result != null && result == 1;
        } catch (Exception e) {
            // Handle exceptions
            return false;
        }
    }
?
    public void unlock(String lockKey, String lockValue) {
        try {
            //拿到鎖的線程才可以釋放鎖,lockValue 可以設(shè)置為 uuid。
            String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            RedisScript<Long> redisScript = new DefaultRedisScript<>(luaScript, Long.class);
            redisTemplate.execute(redisScript, Collections.singletonList(lockKey), lockValue);
        } catch (Exception e) {
            // Handle exceptions
        }
    }
}

方案二:Redisson

Redisson 是一個(gè)基于 Java 的客服端,通過(guò) Redisson 我們可以快速安全的實(shí)現(xiàn)分布式鎖。Redisson 框架具有可重入鎖的支持、分布式鎖的實(shí)現(xiàn)、鎖的自動(dòng)續(xù)期、紅鎖支持等多種特點(diǎn),給我們開(kāi)發(fā)過(guò)程中帶來(lái)了極大的便利。

@Component
public class RedisLock {
?
    @Resource
    private RedissonClient redissonClient;
?
    /**
     * lock(), 拿不到lock就不罷休,不然線程就一直block
     */
    public RLock lock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock();
        return lock;
    }
?
    /**
     * leaseTime為加鎖時(shí)間,單位為秒
     */
    public RLock lock(String lockKey, long leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(leaseTime, TimeUnit.SECONDS);
        return null;
    }
?
    /**
     * timeout為加鎖時(shí)間,時(shí)間單位由unit確定
     */
    public RLock lock(String lockKey, TimeUnit unit, long timeout) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(timeout, unit);
        return lock;
    }
?
    /**
     * @param lockKey   鎖 key
     * @param unit      單位
     * @param waitTime  等待時(shí)間
     * @param leaseTime 鎖有效時(shí)間
     * @return 加鎖成功? true:成功 false: 失敗
     */
    public boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime) {
?
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            return false;
        }
    }
?
    /**
     * unlock
     */
    public void unlock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        if (lock.isLocked() && lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }
?
    /**
     * unlock
     * @param lock 鎖
     */
    public void unlock(RLock lock) {
        lock.unlock();
    }
}

方案三:RedLock

RedLock 又叫做紅鎖,是 Redis 官方提出的一種分布式鎖的算法,紅鎖的提出是為了解決集群部署中 Redis 鎖相關(guān)的問(wèn)題。

比如當(dāng)線程 A 請(qǐng)求鎖成功了,這時(shí)候從節(jié)點(diǎn)還沒(méi)有復(fù)制鎖。此時(shí)主節(jié)點(diǎn)掛掉了,從節(jié)點(diǎn)成為了主節(jié)點(diǎn)。線程 B 請(qǐng)求加鎖,在原來(lái)的從節(jié)點(diǎn)(現(xiàn)在是主節(jié)點(diǎn))上加鎖成功。這時(shí)候就會(huì)出現(xiàn)線程安全問(wèn)題。

下圖是紅鎖的簡(jiǎn)易思路。紅鎖認(rèn)為 (N / 2) + 1 個(gè)節(jié)點(diǎn)加鎖成功后,那么就認(rèn)為獲取到了鎖,通過(guò)這種算法減少線程安全問(wèn)題。簡(jiǎn)單流程為:

  • 順序向五個(gè)節(jié)點(diǎn)請(qǐng)求加鎖
  • 根據(jù)一定的超時(shí)時(shí)間判斷是否跳過(guò)該節(jié)點(diǎn)
  • (N / 2) + 1 個(gè)節(jié)點(diǎn)加鎖成功并且小于鎖的有效期
  • 認(rèn)定加鎖成功

@Service
public class MyService {
?
    private final RedissonClient redissonClient;
?
    @Autowired
    public MyService(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }
?
    public void doSomething() {
        RLock lock1 = redissonClient.getLock("lock1");
        RLock lock2 = redissonClient.getLock("lock2");
        RLock lock3 = redissonClient.getLock("lock3");
?
        RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
        redLock.lock();
        try {
            // 業(yè)務(wù)邏輯
        } finally {
            redLock.unlock();
        }
    }
}

總結(jié)

自己玩或者測(cè)試的時(shí)候使用方案一的簡(jiǎn)單實(shí)現(xiàn)。

單機(jī)版 Redis 使用方案二。

Redis 集群使用方案三。

以上就是Java實(shí)現(xiàn)Redis分布式鎖的三種方案匯總的詳細(xì)內(nèi)容,更多關(guān)于Redis分布式鎖的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • servlet簡(jiǎn)單實(shí)現(xiàn)文件下載的方法

    servlet簡(jiǎn)單實(shí)現(xiàn)文件下載的方法

    這篇文章主要介紹了servlet簡(jiǎn)單實(shí)現(xiàn)文件下載的方法,涉及基于servlet技術(shù)實(shí)現(xiàn)流形式文件傳輸?shù)南嚓P(guān)操作技巧,需要的朋友可以參考下
    2016-12-12
  • Java中超高頻常見(jiàn)字符操作合集(建議收藏)

    Java中超高頻常見(jiàn)字符操作合集(建議收藏)

    這篇文章主要為大家詳細(xì)介紹了Java中超高頻常見(jiàn)字符操作合集,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)java有一定的幫助,需要的小伙伴可以參考下
    2023-10-10
  • 使用Prometheus+Grafana的方法監(jiān)控Springboot應(yīng)用教程詳解

    使用Prometheus+Grafana的方法監(jiān)控Springboot應(yīng)用教程詳解

    這篇文章主要介紹了用Prometheus+Grafana的方法監(jiān)控Springboot應(yīng)用,本文通過(guò)實(shí)例代碼詳解給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • JAVA實(shí)現(xiàn)的簡(jiǎn)單萬(wàn)年歷代碼

    JAVA實(shí)現(xiàn)的簡(jiǎn)單萬(wàn)年歷代碼

    這篇文章主要介紹了JAVA實(shí)現(xiàn)的簡(jiǎn)單萬(wàn)年歷代碼,涉及Java日期操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-10-10
  • 微服務(wù)SpringConfig配置中心詳解

    微服務(wù)SpringConfig配置中心詳解

    這篇文章主要介紹了微服務(wù)SpringConfig配置中心,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • 一文搞懂Java中的反射機(jī)制

    一文搞懂Java中的反射機(jī)制

    這篇文章主要介紹了Java中反射機(jī)制的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-08-08
  • Spring-Boot框架初步搭建

    Spring-Boot框架初步搭建

    本篇文章主要介紹了Spring-Boot框架初步搭建,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-03-03
  • Java中的hashcode方法介紹

    Java中的hashcode方法介紹

    這篇文章主要介紹了Java中的hashcode方法介紹,還是比較不錯(cuò)的,這里分享給大家,供需要的朋友參考。
    2017-11-11
  • Mybatis generator如何自動(dòng)生成代碼

    Mybatis generator如何自動(dòng)生成代碼

    這篇文章主要介紹了Mybatis generator如何自動(dòng)生成代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-12-12
  • SpringBoot常用計(jì)量與bean屬性校驗(yàn)和進(jìn)制數(shù)據(jù)轉(zhuǎn)換規(guī)則全面分析

    SpringBoot常用計(jì)量與bean屬性校驗(yàn)和進(jìn)制數(shù)據(jù)轉(zhuǎn)換規(guī)則全面分析

    這篇文章主要介紹了SpringBoot常用計(jì)量、bean屬性校驗(yàn)與進(jìn)制數(shù)據(jù)轉(zhuǎn)換規(guī)則,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2022-10-10

最新評(píng)論

奇台县| 中江县| 伊川县| 威信县| 永定县| 博爱县| 云霄县| 湘潭县| 青阳县| 东乡县| 霸州市| 广元市| 安远县| 喜德县| 郯城县| 新绛县| 仁寿县| 临湘市| 红桥区| 贵州省| 城口县| 巴彦淖尔市| 都安| 内黄县| 肥东县| 横山县| 江津市| 丹阳市| 巴塘县| 乌海市| 焦作市| 佛坪县| 霸州市| 邵武市| 平武县| 罗城| 通河县| 洪雅县| 玛沁县| 九江市| 灵武市|