国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Redis學(xué)習(xí)(八)Java三種方式實(shí)現(xiàn)分布式鎖

這篇具有很好參考價值的文章主要介紹了Redis學(xué)習(xí)(八)Java三種方式實(shí)現(xiàn)分布式鎖。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

一、背景

在分布式服務(wù)中,經(jīng)常有例如定時任務(wù)這樣的場景。

在定時任務(wù)中,如果不使用 quartz 這樣的分布式定時工具,只是簡單使用 @Schedule 注解來實(shí)現(xiàn)定時任務(wù),在服務(wù)分布式部署中,就有可能存在定時任務(wù)并發(fā)重復(fù)執(zhí)行問題

對于解決以上場景中的問題,我們引入了分布式鎖。

二、具體實(shí)現(xiàn)

1.RedisTemplate 實(shí)現(xiàn)(非阻塞)

RedisUtils 工具類:

@Component
public class RedisUtils {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 原子性操作 加鎖
     */
    public boolean setIfAbsent(String key, String value, long timeout, TimeUnit unit) {
        return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit));
    }

    /**
     * 原子性操作 解鎖
     */
    public void delete(String key) {
        redisTemplate.delete(key);
    }
}

使用示例:

@Resource
private RedisUtils redisUtils;

public void updateUserWithRedisLock(SysUser sysUser) throws InterruptedException {
    // 1.獲取分布式鎖
    boolean lockSuccess = RedisUtils.setIfAbsent("SysUserLock" + sysUser.getId(), "value", 30, TimeUnit.SECONDS);
    if (lockSeccess) {
        // 加鎖成功...
        // TODO: 業(yè)務(wù)代碼

        // 釋放鎖
        redisUtils.delete("SysUserLock" + sysUser.getId());
    } else {
        // 如果需要阻塞的話,就睡一段時間再重試
        Thread.sleep(100);
        updateUserWithRedisLock(sysUser);
    }
}

setIfAbsent() 方法的作用就是在 lock key 不存在的時候,才會設(shè)置值并返回 true;如果這個 key 已經(jīng)存在了就返回 false,即獲取鎖失敗。


2.RedisLockRegistry 實(shí)現(xiàn)(阻塞)

RedisLockRegistryspring-integration-redis 中提供的 Redis 分布式鎖實(shí)現(xiàn)類。

集成 spring-integration-redis:

<dependency>
	<groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-interation</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-redis</artifactId>
</dependency>

注冊RedisLockRegistry:

@Configuration
public class RedisLockConfig {
    
    @Bean
    public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactor) {
        // 第一個參數(shù) redisConnectionFactory
        // 第二個參數(shù) registryKey,分布式鎖前綴,建議設(shè)置項(xiàng)目名稱
        // 該構(gòu)造方法對應(yīng)的分布式鎖,默認(rèn)有效期是60秒,可以自定義。
        return new RedisLockRegistry(redisConnectionFactory, "boot-launch");
        // return new RedisLockRegistry(redisConnectionFactory, "boot-launch", 60);
    }
}

使用RedisLockRegistry:

代碼實(shí)現(xiàn):

@Resource
private RedisLockRegisty redisLockRegistry;

public void updateUser(String userId) {
    String lockKey = "config" + userId;
    Lock lock = redisLockRegistry.obtain(lockKey); // 獲取鎖資源
    try {
        lock.lock(); // 加鎖
        
        // TODO: 業(yè)務(wù)代碼
    } finally {
        lock.unlock(); // 釋放鎖
    }
}

注解實(shí)現(xiàn):

@RedisLock("lock-key")
public void save() {
    
}

RedisLockRegistry 實(shí)現(xiàn)的分布式鎖是支持阻塞的。RedisLocckRegistry 是 Spring Integration Redis 模塊中的一個類,它是基于 Redis 實(shí)現(xiàn)的分布式鎖機(jī)制。

當(dāng)一個線程嘗試獲取分布式鎖時,如果該鎖已經(jīng)被其他線程占用,則當(dāng)前線程會被阻塞,等待鎖釋放。阻塞的線程會一直等待,直到鎖被成功獲取或者等待超時。

阻塞的實(shí)現(xiàn)是通過 Redis 的特性實(shí)現(xiàn)的:通過 Redis 的 SETNX 命令(SET if Not eXists)嘗試將鎖的鍵值對設(shè)置到 Redis 中。如果設(shè)置成功,則表示獲取鎖成功;如果設(shè)置失敗,則表示鎖已被其他線程占用,當(dāng)前線程會被阻塞。

因此,使用 RedisLockRegistry 可以實(shí)現(xiàn)支持阻塞的分布式鎖機(jī)制,能夠?qū)崿F(xiàn)多線程之間的協(xié)調(diào)和互斥。


3.Redisson 實(shí)現(xiàn)(阻塞)

Redission 是一個獨(dú)立的 Redis 客戶端,是與 Jedis、Lettuce 同級別的存在。

集成 Redisson:

<dependency>
	<groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.15.0</version>
    <exclusions>
    	<exclusion>
        	<groupId>org.redisson</groupId>
            <!-- 默認(rèn)是 Spring Data Redis v.2.3.x 所以排除掉 -->
            <artifactId>redisson-spring-data-23</artifactId>
        </exclusion>
    </exclusions>
</dependency>

配置:

1)在配置文件中添加如下內(nèi)容:

spring:
  redis:
    redisson:
      file: classpath:redisson.yaml

2)然后新建一個 redisson.yaml 文件,也放在 resources 目錄下:

singleServerConfig:
  idleConnectionTimeout: 10000
  connectTimeout: 10000
  timeout: 3000
  retryAttempts: 3
  retryInterval: 1500
  password: 123456
  subscriptionsPerConnection: 5
  clientName: null
  address: "redis://192.168.161.3:6379"
  subscriptionConnectionMinimumIdleSize: 1
  subscriptionConnectionPoolSize: 50
  connectionMinimumIdleSize: 32
  connectionPoolSize: 64
  database: 0
  dnsMonitoringInterval: 5000
threads: 0
nettyThreads: 0
codec: !<org.redisson.codec.JsonJacksonCodec> {}
transportMode: "NIO"

代碼實(shí)現(xiàn):

@Resource
private RedissonClient redissonClient;

public void updateUser(String userId) {
    String lockKey = "config" + userId;
    RLock lock = redissonClient.getLock(lockKey); // 獲取鎖資源
    try {
        lock.lock(10, TimeUnit.SECONDS); // 加鎖,可以指定鎖定時間
        
        // TODO: 業(yè)務(wù)代碼
    } finally {
        lock.unlock(); // 釋放鎖
    }
}

對比 RedisLockRegistry 和 Redisson 實(shí)現(xiàn):

  • Redisson 優(yōu)點(diǎn):可以為每一個鎖指定不同的超時時間,而 RedisLockRegistry 目前只能針對所有的鎖設(shè)置統(tǒng)一的超時時間。

注意:如果業(yè)務(wù)執(zhí)行超時之后,再去 unlock 會拋出 java.lang.IllegalMonitorStateException。

三、思考

1.為什么可以用 setIfAbsent(),而不能用 setnx() ?

  • setIfAbsent() 是 Redis 專門為分布式鎖實(shí)現(xiàn)的原子操作,其中封裝了獲取 key、設(shè)置 key、設(shè)置過期時間等操作。
  • setnx() 主要用于分布式 ID 的生成,如果要用來實(shí)現(xiàn)分布式鎖的話,雖然可以通過返回結(jié)果為0表示獲取鎖失敗,1表示獲取鎖成功,但是對于設(shè)置過期時間的操作需要手動實(shí)現(xiàn),無法保證原子性。

整理完畢,完結(jié)撒花~ ??





參考地址:

1.Java三種方式實(shí)現(xiàn)redis分布式鎖,https://blog.csdn.net/w_monster/article/details/124472493文章來源地址http://www.zghlxwxcb.cn/news/detail-657752.html

到了這里,關(guān)于Redis學(xué)習(xí)(八)Java三種方式實(shí)現(xiàn)分布式鎖的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • JAVA微服務(wù)分布式事務(wù)的幾種實(shí)現(xiàn)方式

    JAVA微服務(wù)分布式事務(wù)的幾種實(shí)現(xiàn)方式

    一致性(Consistency) :在分布式系統(tǒng)中所有的數(shù)據(jù)備份,在同一時刻都保持一致狀態(tài),如無法保證狀態(tài)一致,直接返回錯誤; 可用性(Availability):在集群中一部分節(jié)點(diǎn)故障,也能保證客戶端訪問系統(tǒng)并得到正確響應(yīng),允許一定時間內(nèi)數(shù)據(jù)狀態(tài)不一致; 分區(qū)容錯性(Partiti

    2024年02月12日
    瀏覽(20)
  • hive-3.1.2分布式搭建與hive的三種交互方式

    hive-3.1.2分布式搭建與hive的三種交互方式

    在官網(wǎng)或者鏡像站下載驅(qū)動包 華為云鏡像站地址: hive: Index of apache-local/hive/hive-3.1.2 mysql驅(qū)動包: Index of mysql-local/Downloads/Connector-J # 1、解壓 tar -zxvf apache-hive-3.1.2-bin.tar.gz -C /usr/local/soft/ # 2、重名名 mv apache-hive-3.1.2-bin hive-3.1.2 # 3、配置環(huán)境變量 vim /etc/profile # 4、在最后增加

    2024年04月16日
    瀏覽(24)
  • pytorch 進(jìn)行分布式調(diào)試debug torch.distributed.launch 三種方式

    pytorch 進(jìn)行分布式調(diào)試debug torch.distributed.launch 三種方式

    一. pytorch 分布式調(diào)試debug torch.distributed.launch 三種方式 1. 方式1:ipdb調(diào)試(建議) 參考之前的博客:python調(diào)試器 ipdb 注意:pytorch 分布式調(diào)試只能使用侵入式調(diào)試,也即是在你需要打斷點(diǎn)的地方(或者在主程序的第一行)添加下面的代碼: 當(dāng)進(jìn)入pdb調(diào)試后,跟原先使用pdb調(diào)試

    2024年02月07日
    瀏覽(41)
  • Java中利用Redis,ZooKeeper,數(shù)據(jù)庫等實(shí)現(xiàn)分布式鎖(遙遙領(lǐng)先)

    Java中利用Redis,ZooKeeper,數(shù)據(jù)庫等實(shí)現(xiàn)分布式鎖(遙遙領(lǐng)先)

    1.1 什么是分布式鎖 在我們進(jìn)行單機(jī)應(yīng)用開發(fā)涉及并發(fā)同步的時候,我們往往采用synchronized或者ReentrantLock的方式來解決多線程間的代碼同步問題。但是當(dāng)我們的應(yīng)用是在分布式集群工作的情況下,那么就需要一種更加高級的鎖機(jī)制,來處理種跨機(jī)器的進(jìn)程之間的數(shù)據(jù)同步問題

    2024年02月03日
    瀏覽(26)
  • Redis——》Redis的部署方式對分布式鎖的影響

    Redis——》Redis的部署方式對分布式鎖的影響

    推薦鏈接: ????總結(jié)——》【Java】 ????總結(jié)——》【Mysql】 ????總結(jié)——》【Redis】 ????總結(jié)——》【Kafka】 ????總結(jié)——》【Spring】 ????總結(jié)——》【SpringBoot】 ????總結(jié)——》【MyBatis、MyBatis-Plus】 ????總結(jié)——》【Linux】 ????總結(jié)——》【MongoDB】 ???

    2024年02月10日
    瀏覽(24)
  • 分布式鎖設(shè)計選型 不可重入鎖建議使用ZooKeeper來實(shí)現(xiàn) 可重入鎖建議使用Redis來實(shí)現(xiàn) 分布式鎖:ZooKeeper不可重入鎖 Java優(yōu)化建議

    在設(shè)計分布式鎖時,需要考慮業(yè)務(wù)場景和業(yè)務(wù)需求,以保證鎖的正確性和可用性。 例如,在一個電商系統(tǒng)中,每個商品都有一個庫存量。為了避免多個用戶同時購買同一件商品導(dǎo)致庫存出現(xiàn)不一致的情況,可以為每個商品設(shè)置一個分布式鎖,確保同一時間只能有一個用戶購買

    2024年02月08日
    瀏覽(21)
  • 分布式學(xué)習(xí)第二天 redis學(xué)習(xí)

    分布式學(xué)習(xí)第二天 redis學(xué)習(xí)

    目錄 1. 數(shù)據(jù)庫類型 1.1 基本概念 1.2 關(guān)系/非關(guān)系型數(shù)據(jù)庫搭配使用 2. Redis ? 2.1 基本知識點(diǎn) 2.2 redis常用命令 2.4 redis數(shù)據(jù)持久化 3 hiredis的使用 4. 復(fù)習(xí) 1. 數(shù)據(jù)庫類型 1.1 基本概念 關(guān)系型數(shù)據(jù)庫 - sql 操作數(shù)據(jù)必須要使用sql語句 數(shù)據(jù)存儲在磁盤 存儲的數(shù)據(jù)量大 舉例: mysql oracle s

    2024年02月09日
    瀏覽(24)
  • Redis學(xué)習(xí)路線(6)—— Redis的分布式鎖

    Redis學(xué)習(xí)路線(6)—— Redis的分布式鎖

    一、分布式鎖的模型 (一)悲觀鎖: 認(rèn)為線程安全問題一定會發(fā)生,因此在操作數(shù)據(jù)之前先獲取鎖,確保線程串行執(zhí)行。例如Synchronized、Lock都屬于悲觀鎖。 優(yōu)點(diǎn): 簡單粗暴 缺點(diǎn): 性能略低 (二)樂觀鎖: 認(rèn)為線程安全問題不一定會發(fā)生,因此不加鎖,只有在更新數(shù)據(jù)時

    2024年02月14日
    瀏覽(25)
  • 分布式鎖實(shí)現(xiàn)(mysql,以及redis)以及分布式的概念

    分布式鎖實(shí)現(xiàn)(mysql,以及redis)以及分布式的概念

    我旁邊的一位老哥跟我說,你知道分布式是是用來干什么的嘛?一句話給我干懵了,我能隱含知道,大概是用來做分壓處理的,并增加系統(tǒng)穩(wěn)定性的。但是具體如何,我卻道不出個1,2,3。現(xiàn)在就將這些做一個詳細(xì)的總結(jié)。至少以后碰到面試官可以說上個123。 那么就正式進(jìn)入

    2024年01月21日
    瀏覽(37)
  • Redis——》實(shí)現(xiàn)分布式鎖

    推薦鏈接: ????總結(jié)——》【Java】 ????總結(jié)——》【Mysql】 ????總結(jié)——》【Redis】 ????總結(jié)——》【Kafka】 ????總結(jié)——》【Spring】 ????總結(jié)——》【SpringBoot】 ????總結(jié)——》【MyBatis、MyBatis-Plus】 ????總結(jié)——》【Linux】 ????總結(jié)——》【MongoDB】 ???

    2024年02月10日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包