成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Spring Boot Redis實現分布式鎖,真香!!

開發 后端 分布式 Redis
本篇棧長以 Redis 為例(這也是用得最多的方案),教大家如何利用 Spring Boot 集成 Redis 實現緩存,如何簡單、快速實現 Redis 分布式鎖。

之前看很多人手寫分布式鎖,其實 Spring Boot 現在已經做的足夠好了,開箱即用,支持主流的 Redis、Zookeeper 中間件,另外還支持 JDBC。

本篇棧長以 Redis 為例(這也是用得最多的方案),教大家如何利用 Spring Boot 集成 Redis 實現緩存,如何簡單、快速實現 Redis 分布式鎖。

分布式鎖介紹

Spring Boot 實現 Redis 分布式鎖在 spring-integration 這個項目中,參考:

https://docs.spring.io/spring-integration/docs/5.3.1.RELEASE/reference/html/redis.html#redis-lock-registry

首先來看下 LockRegistry 鎖注冊接口的所有實現類結構圖:

DefaultLockRegistry 就是純單機的可重入鎖,PassThruLockRegistry 是一個空實現類,也都沒有什么利用價值。

Spring Integration 4.0 引入了基于 Redis 的分布式鎖:RedisLockRegistry,并且從 5.0 開始實現了 ExpirableLockRegistry 接口,用來移除超時且沒有用的鎖。

分布式鎖實戰

添加依賴

上面提到 Spring Boot 實現 Redis 分布式鎖在 spring-integration 這個項目中,所以需要這三個依賴:

  •  spring-boot-starter-data-redis
  •  spring-boot-starter-integration
  •  spring-integration-redis 
  1. <dependency>  
  2.  <groupId>org.springframework.boot</groupId>  
  3.  <artifactId>spring-boot-starter-data-redis</artifactId>  
  4. </dependency>  
  5. <dependency>  
  6.  <groupId>org.springframework.boot</groupId>  
  7.  <artifactId>spring-boot-starter-integration</artifactId> 
  8. </dependency>  
  9. <dependency>  
  10.  <groupId>org.springframework.integration</groupId>  
  11.  <artifactId>spring-integration-redis</artifactId>  
  12. </dependency> 

Spring Boot 基礎知識就不介紹了,不熟悉的可以關注公眾號Java技術棧,在后臺回復:boot,可以閱讀我寫的歷史實戰教程。

配置分布式鎖 

  1. @Bean(destroyMethod = "destroy" 
  2. public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) {  
  3.     return new RedisLockRegistry(redisConnectionFactory, "lock");  

使用示例 

  1. @GetMapping("/redis/lock")  
  2. public String lock(@RequestParam("key") String key) {  
  3.     for (int i = 0; i < 10; i++) {  
  4.         new Thread(() -> {  
  5.             redisLockService.lock(key);  
  6.             try {  
  7.                 Thread.sleep(3000L);  
  8.             } catch (InterruptedException e) {  
  9.                 e.printStackTrace();  
  10.             }  
  11.             System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));  
  12.             redisLockService.unlock(key);  
  13.         }  
  14.         ).start();  
  15.     }  
  16.     return "OK";  

RedisLockService 是我封裝了的一個 Redis 鎖服務,代碼有點多,這里就不貼了,完整的代碼示例在 Github 上,大家可以 Star 一下:

https://github.com/javastacks/spring-boot-best-practice

測試:

http://localhost:8080/redis/lock?key=yeah

輸出: 

  1. 2020-06-23 11:15:34  
  2. 2020-06-23 11:15:37  
  3. 2020-06-23 11:15:40  
  4. 2020-06-23 11:15:43  
  5. 2020-06-23 11:15:46  
  6. 2020-06-23 11:15:49  
  7. 2020-06-23 11:15:52  
  8. 2020-06-23 11:15:55 
  9. 2020-06-23 11:15:58  
  10. 2020-06-23 11:16:01 

可以看到每個線程需要等上一個線程休眠 3 秒后才能獲取到鎖。

源碼分析

集成完了,會使用了,還得研究下 RedisLockRegistry 的源碼,不然遇到什么坑還得再踩一篇。

RedisLockRegistry 有兩個類構造器:

  •  connectionFactory:Redis 連接工廠
  •  registryKey:鎖前綴
  •  expireAfter:失效時間(非必須項,默認60秒)

所以,我們要注冊 expireAfter 這個選項,默認 60 秒是否滿足業務需要,如果超過默認的 60 少時間,否則將導致鎖失效。

還有兩個和 RedisLockRegistry  相關且很重要的成員變量: 

  1. private final String clientId = UUID.randomUUID().toString();  
  2. private final Map<String, RedisLock> locks = new ConcurrentHashMap<>(); 
  •  clientId:

首先用來標識當前 RedisLockRegistry 實例ID,并且在設置、移除鎖的時候都會要用到,用來判斷是不是當前的鎖注冊實例。

  •  locks:

用來在內存中緩存當前鎖注冊實例所有鎖對象。

獲取鎖對象

如下面獲取鎖對象源碼所示:

每個 key 在內存中(ConcurrentHashMap)都對應一個鎖對象,鎖對象有生成過就直接返回,沒有就生成再返回,有了這個鎖對象才能進行上鎖和解鎖操作。

這個鎖對象(RedisLock)其實也是實現了 Java 中的 java.util.concurrent.locks.Lock 鎖接口:

鎖對象(RedisLock)也有兩個很重要的成員變量: 

  1. private final ReentrantLock localLock = new ReentrantLock();  
  2. private volatile long lockedAt; 
  •  localLock:

localLock 是一個本地內存可重入鎖,每次去 Redis 上鎖前,都要用本地 localLock 上鎖先,這樣能做到盡可能的少往 Redis 上鎖,也能從一方面提升鎖的性能。

  •  lockedAt:

lockedAt 上鎖時間,移除過時鎖會用到。

阻塞上鎖

RedisLock#lock():

每隔 100 毫秒嘗試獲取一次鎖,直到獲取鎖成功為止,不接受打斷異常,遇到其他異常會釋放本地鎖返回異常并結束。

主要看下設置 Redis 鎖的 Lua 腳本:

根據 key 查詢其對應的值:clientId,如果和當前 clientId 一致則延長失效時間,如果 clientId 不存在就直接上鎖,以上都不成立返回 false。

這樣做的好處是,可以將整個 Redis Lua 腳本作為一個原子執行,而不用考慮并發及事務影響。

好了,核心的源碼分析完了,其實也很簡單,大家還不懂的或者有興趣的可以再研究下。

本文完整示例源代碼和上篇 Spring Boot 快速集成 Redis 的示例代碼一起上傳到了 Github,歡迎大家 Star 關注學習。

https://github.com/javastacks/spring-boot-best-practice

所以,你還在手寫分布式鎖嗎?趕快 Get 起來吧! 

 

責任編輯:龐桂玉 來源: Java技術棧
相關推薦

2022-10-10 14:41:44

RedisJVM數據

2023-10-12 10:32:51

2022-01-06 10:58:07

Redis數據分布式鎖

2023-08-21 19:10:34

Redis分布式

2022-09-22 13:28:34

Redis分布式鎖

2022-09-29 08:28:57

SpringRedis分布式

2024-01-30 08:41:33

線程執行Redis分布式鎖

2019-02-26 09:51:52

分布式鎖RedisZookeeper

2019-06-19 15:40:06

分布式鎖RedisJava

2024-10-07 10:07:31

2024-04-01 05:10:00

Redis數據庫分布式鎖

2020-07-30 09:35:09

Redis分布式鎖數據庫

2023-03-01 08:07:51

2023-01-13 07:39:07

2023-10-11 09:37:54

Redis分布式系統

2019-12-25 14:35:33

分布式架構系統

2021-10-25 10:21:59

ZK分布式鎖ZooKeeper

2024-11-28 15:11:28

2022-03-24 07:51:27

seata分布式事務Java

2022-09-19 08:17:09

Redis分布式
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美日韩视频在线第一区 | 九九综合九九 | 精品av久久久久电影 | 欧美成人一级 | 中文字幕一区在线 | 97色在线观看免费视频 | 久久激情网 | 亚洲综合在线视频 | 狠狠干狠狠操 | 久久最新网址 | 久久国产一区二区 | 亚洲色欲色欲www | 伊人久久免费 | 尤物视频在线免费观看 | 日韩三级 | 国产91中文| 精品久久99 | 国产高清视频 | 久久精品国产一区二区三区不卡 | 久久99精品视频 | 精品亚洲二区 | 国产aa | 成人伊人 | 亚洲一级毛片 | 一级女毛片| 黑人一级黄色大片 | 国产一区不卡 | 亚洲成人免费 | 国产精品国产成人国产三级 | 一区二区三区四区在线视频 | 免费看国产a | 天天夜夜人人 | 天天艹天天干天天 | 在线播放国产一区二区三区 | 祝你幸福电影在线观看 | 久久国产电影 | 久久久久久国产一区二区三区 | 精品网 | 91在线看 | 国产精品视频久久久久 | 欧美中文字幕一区二区 |