Redisson實現分布式鎖示例

一、引入依賴

        <dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.16.0</version></dependency>

二、配置類

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;/*** @Author ZGM* @DateTime 2023/8/15* @description*/
@Configuration
public class RedissonConfig {@Beanpublic RedissonClient redissonClient(){// 配置,Config config = new Config();//單例模式config.useSingleServer().setAddress("redis://127.0.0.1:6379");// .setPassword("123456");//修改看門狗的默認時間30s到60s//config.setLockWatchdogTimeout(60000);// 創建RedissonClient對象return Redisson.create(config);}//這個只針對轉化為string類型@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<String, Object> template = new RedisTemplate();template.setConnectionFactory(redisConnectionFactory);//默認是JDK序列化  發現key和value前面都多了一串特殊字符StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();template.setKeySerializer(stringRedisSerializer);template.setValueSerializer(stringRedisSerializer);return template;}
}

三、實現類

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;/*** @Author ZGM* @DateTime 2023/8/15* @description*/
@Service
@Slf4j
public class UserService {@Autowiredprivate RedissonClient redissonClient;@AutowiredRedisTemplate<String, Object> redisTemplate;public void test1() throws InterruptedException {//定義一個keyString key = UUID.randomUUID().toString();// 占鎖 沒有拿到鎖的會自動阻塞// watchDog 機制 : 鎖自動加了默認30秒過期// 如果業務代碼耗時長,鎖也會自動續期RLock lock = redissonClient.getLock(key);//只有lock()和tryLock(5000, TimeUnit.MILLISECONDS)會觸發看門狗機制Boolean isLocked = lock.tryLock(5000, TimeUnit.MILLISECONDS);if(!isLocked) {log.info("獲取鎖失敗");}long a = System.currentTimeMillis();try {Thread.sleep(60000);} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}long b = System.currentTimeMillis();System.out.println(b-a);}}

四、測試結果

可以下載redis desktop manager軟件來查看redis里面存放的東西
在這里插入圖片描述
紅色框內的TTL值就是過期時間,默認-1,表示永不過期,指定過期時間后就變成你指定的值了。

上面的方法,我們讓線程睡眠60S,代表我們的業務執行時間,在調用這個方法時,我們可以在
redis desktop manager軟件上實時查看鎖的過期時間,第一次過期時間為30S,10S后刷新過期時間為30S,也就是說,它每隔10S會檢驗這個鎖是否釋放,沒有的話,會一直給你刷新鎖的持有時間變為30S,直到任務完成。

五、看門狗機制

上面所說的自動刷新鎖的持有時間,就是通過這個看門狗機制來實現的。它默認的鎖的持有時間是30S,每隔30/3也就是10S會刷新鎖的持有時間,我們也可以通過redisson的Config 類的config.setLockWatchdogTimeout(60000)來修改過期時間。實際上鎖的持有時間就是lockWatchdogTimeout的值,只不過默認設置的30S而已,同樣的,鎖的刷新時間也是每隔lockWatchdogTimeout/3秒執行一次,如果設置的時間為60S,就是鎖的過期時間為60S,每隔20S執行一次。
所謂的自動刷新,其實是在獲取鎖的時候,開了一個線程來監控這個鎖,我們先按照默認的30S過期時間來計算,假設當前業務的執行時間在10S之內,在第10S時此線程監控到該鎖已被正常釋放,則不會刷新鎖的過期時間,反之,在第10S時此線程監控到該鎖仍被此線程持有,那也就是業務還未執行完,它就會幫你刷新過期時間。即使redis的服務器宕機了,也不會出現死鎖,因為當它監控到異常時,也不會刷新過期時間,當redis的服務器恢復時,自動就把它刪除了。

六、注意

注意:只有只有lock()和tryLock(waitTime, TimeUnit.MILLISECONDS)會觸發看門狗機制,在這兩個方法里我們都沒有指定releaseTime,它默認值就是-1,然后才能自動觸發看門狗機制,或者我們在調用獲取鎖的方法時直接指定releaseTime為-1,這樣也可以觸發看門狗機制,一定要注意這一點。
lock()會一直嘗試獲取鎖,知道成功
tryLock(long time, TimeUnit unit),同樣會一直嘗試獲取鎖,但它有等待時間,超過這個時間就直接返回false,不在繼續調用,我比較喜歡這個方法。

七、建議

看門狗機制雖然可以自動刷新鎖的過期時間,用起來也非常方便,但并不是說,所有的方法,都應該開啟此機制。因為啟動此機制的同時,意味著會額外開啟一個線程來監控它,那么就會占用CPU內存。少量線程的情況下,這部分內存占用可以忽略,當請求過多時,就占用比略高了,只能增加服務器,也就是增加成本了。

所以我建議是,在獲取資源的方法里,不開啟看門狗機制,比如,一個接口是返回個人信息的,那么我在調用時,由于某種原因導致鎖已經釋放,但業務還未執行完成,那么會報錯,
信息如下:[Request processing failed; nested exception is java.lang.IllegalMonitorStateException: attempt to unlock lock, not locked by current thread by node id: 62e61f35-6cd5-4fc2-849e-78ad649435e4 thread-id: 72] with root cause,我們直接捕獲此異常,返回系統繁忙即可。

在更新或者保存資源的方法里,是可以開啟看門狗機制的,這樣雖然執行時間會稍微長一些,但最終會完成任務,不至于讓用戶重復操作。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/42677.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/42677.shtml
英文地址,請注明出處:http://en.pswp.cn/news/42677.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用opencv進行文本增強

文本增強: import cv2 import numpy as np# 讀取圖像 image = cv2.imread(E:/image.jpg, cv2.IMREAD_GRAYSCALE)# 二值化圖像 _, binary_image = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)# 膨脹操作 kernel = np.ones((3, 3), np.uint8) dilated_…

Python Flask藍圖使用

使用示例&#xff1a; user.py from utils.sql import supabase from flask import Blueprint,request, session from utils.entity import r user_bp Blueprint(user, __name__, url_prefix/user)"""----------------------------------------API: 用戶登錄…

Hadoop學習:深入解析MapReduce的大數據魔力(三)

Hadoop學習&#xff1a;深入解析MapReduce的大數據魔力&#xff08;三&#xff09; 3.5 MapReduce 內核源碼解析3.5.1 MapTask 工作機制3.5.2 ReduceTask 工作機制3.5.3 ReduceTask 并行度決定機制 3.6 數據清洗&#xff08;ETL&#xff09;1&#xff09;需求2&#xff09;需求…

uni-app封裝api請求

前端封裝api請求 前端封裝 API 請求可以提高代碼的可維護性和重用性&#xff0c;同時使得 API 調用更加簡潔和易用。 下面是一種常見的前端封裝 API 請求的方式&#xff1a; 創建一個 API 封裝模塊或類&#xff1a;可以使用 JavaScript 或 TypeScript 創建一個獨立的模塊或類來…

Java數據庫連接池原理及spring boot使用數據庫連接池(HikariCP、Druid)

和線程池類似&#xff0c;數據庫連接池的作用是建立一些和數據庫的連接供需要連接數據庫的業務使用&#xff0c;避免了每次和數據庫建立、銷毀連接的性能消耗&#xff0c;通過設置連接池參數可以防止建立連接過多導致服務宕機等&#xff0c;以下介紹Java中主要使用的幾種數據庫…

【學習FreeRTOS】第11章——FreeRTOS中任務相關的其他API函數

1.函數總覽 序號函數描述1uxTaskPriorityGet()獲取任務優先級2vTaskPrioritySet()設置任務優先級3uxTaskGetNumberOfTasks()獲取系統中任務的數量4uxTaskGetSystemState()獲取所有任務的狀態信息5vTaskGetInfo()獲取單個任務的狀態信息6xTaskGetCurrentTaskHandle()獲取當前任…

Excel自動化辦公——Openpyxl的基本使用

Excel自動化辦公——Openpyxl的基本使用 個人感覺&#xff0c;相比Pandas&#xff0c;openpyxl對Excel的操作更為細致&#xff0c;Pandas則更適用于統計計算&#xff1b; 01 基本環境02 Excel數據讀取操作03 案例04 向Excel寫入數據05 表數據定向修改06 單元格樣式制定07 單元…

原型對象的簡單了解

在前面學習java有一個概念叫做繼承&#xff0c;方便我們對父類方法、變量等的調用。對前端的學習我們需要讓對象可以訪問和繼承其他對象的屬性和方法&#xff0c;就需要了解原型對象&#xff0c;以及原型鏈。 一、原型 構造函數通過原型分配的函數是所有對象所共享的。每一個構…

【Lua語法】算術、條件、邏輯、位、三目運算符

1.算術運算符 加減乘除取余&#xff1a; - * / % Lua中獨有的&#xff1a;冪運算 ^ 注意&#xff1a; 1.Lua中沒有自增自減(、–)&#xff0c;也沒有復合運算符(、-) 2.Lua中字符串可以進行算術運算符操作&#xff0c;會自動轉成number 如&#xff1a;“10.3” 1 結果為11.3…

回歸預測 | MATLAB實現SOM-BP自組織映射結合BP神經網絡多輸入單輸出回歸預測(多指標,多圖)

回歸預測 | MATLAB實現SOM-BP自組織映射結合BP神經網絡多輸入單輸出回歸預測&#xff08;多指標&#xff0c;多圖&#xff09; 目錄 回歸預測 | MATLAB實現SOM-BP自組織映射結合BP神經網絡多輸入單輸出回歸預測&#xff08;多指標&#xff0c;多圖&#xff09;效果一覽基本介紹…

【css動畫】向下的動態箭頭

前言 使用css實現一組向下的動態箭頭效果&#xff0c;如下圖 思路 1.使用svg畫箭頭 2.設置keyframes&#xff0c;主要是每個箭頭加不同的延時。 代碼 <div class"down-arrow"><svg id"more-arrows"><polygonclass"arrow-top&quo…

Spark第三課

1.分區規則 1.分區規則 shuffle 1.打亂順序 2.重新組合 1.分區的規則 默認與MapReduce的規則一致,都是按照哈希值取余進行分配. 一個分區可以多個組,一個組的數據必須一個分區 2. 分組的分區導致數據傾斜怎么解決? 擴容 讓分區變多修改分區規則 3.HashMap擴容為什么必須…

[JavaWeb]【七】web后端開發-MYSQL

前言&#xff1a;MySQL是一種流行的關系型數據庫管理系統,它的作用是存儲和管理數據。在Web開發中,MySQL是必備的數據庫技能之一,因為它可以幫助Web開發人員處理大量的數據,并且提供了強大的數據查詢和管理功能。 一 數據庫介紹 1.1 什么是數據庫 1.2 數據庫產品 二 MySQL概述…

Servlet+JDBC實戰開發書店項目講解第六篇:訂單實現

ServletJDBC實戰開發書店項目講解第六篇&#xff1a;訂單實現 1. 數據庫設計 在訂單實現之前&#xff0c;我們需要對數據庫進行相應的設計。在這個書店項目中&#xff0c;我們可以創建以下兩個表來實現訂單功能&#xff1a; 1.1 訂單表(Order) 訂單ID(order_id)&#xff1a…

vue3 實現簡單瀑布流

一、整理思路 實際場景中&#xff0c;瀑布流一般由 父組件 提供 數據列表&#xff0c;子組件渲染每個圖片都是根據容器進行 絕對定位 &#xff0c;從而定好自己的位置取出 屏幕的寬度&#xff0c;設定 圖片的寬度 固定 為一個值&#xff0c;計算可以鋪 多少列按列數 先鋪上第一…

使用Julia進行核遞歸最小二乘算法(KRLS)的解析與實現

F 標題&#xff1a; 使用Julia進行核遞歸最小二乘算法&#xff08;KRLS&#xff09;的深度解析與實現 第一部分&#xff1a; 核遞歸最小二乘算法 (KRLS) 是一個在線核回歸算法&#xff0c;這種算法的主要特點是能夠一次處理一個樣本&#xff0c;并構建一個訓練點字典&#xf…

5G科技防汛,助力守護一方平安

“立秋雖已至&#xff0c;炎夏尚還在”&#xff0c;受臺風席卷以及季節性影響全國多地正面臨強降水的嚴峻挑戰。“落雨又順秋&#xff0c;綿綿雨不休”&#xff0c;正值“七下八上” 防汛關鍵時期&#xff0c;貴州省水文水資源局已全面進入備戰狀態。 為確保及時響應做好防汛搶…

Vue3 setup新特性簡單應用

去官網學習→組合式 API&#xff1a;setup() | Vue.js 運行示例&#xff1a; 代碼&#xff1a;App.vue <template><div class"home"><img alt"Vue logo" src"../assets/logo.png"><!-- msg 組件傳遞數據 --><Hell…

VBA_MF系列技術資料1-157

MF系列VBA技術資料 為了讓廣大學員在VBA編程中有切實可行的思路及有效的提高自己的編程技巧&#xff0c;我參考大量的資料&#xff0c;并結合自己的經驗總結了這份MF系列VBA技術綜合資料&#xff0c;而且開放源碼&#xff08;MF04除外&#xff09;&#xff0c;其中MF01-04屬于定…

MySQL 面試題

一、數據庫基礎 1、MySQL 有哪些數據庫類型? (1) 整數類型&#xff1a; TINYINT 1 字節 SMALLINT 2 字節 MEDIUMINT 3 字節 INT 4 字節 BIGINT 8 字節 ① 任何整數類型都可以加上 UNSIGNED …