分布式锁-Redisson 可重入锁

news/2024/9/18 13:28:04/ 标签: 分布式

分布式系统中,分布式锁是一种常用的机制,用来在多个实例或服务之间控制共享资源的访问,确保不会出现并发冲突或资源竞争。Redis 是常用的分布式锁实现工具,而 Redisson 是 Redis 的一个 Java 客户端,它提供了强大且易用的分布式锁功能,包括可重入锁、读写锁、公平锁等。

1. 什么是可重入锁

可重入锁(Reentrant Lock),也称为递归锁,是指同一个线程在持有锁的情况下,可以再次获取该锁而不会被锁住。这种锁允许线程重复进入被它锁定的代码块,避免死锁问题。

可重入锁的一个典型应用场景是,某个方法在持有锁时,调用了另一个也需要获取该锁的方法。如果没有可重入特性,这种情况下将会造成死锁。

在 Redisson 中,可重入锁的核心功能是允许线程在持有锁的情况下,能够多次请求同一个锁,而不需要手动释放锁多次。

2. Redisson 可重入锁的特点

  • 可重入性:同一线程可以多次获取同一个锁,锁的计数器会递增。
  • 自动续期:默认情况下,Redisson 的锁会自动为持有锁的线程续期,确保锁在超时前不会被意外释放。
  • 高可用:通过 Redis 集群,Redisson 的分布式锁可以在分布式环境中保证高可用性,支持故障恢复和锁状态的持久化。

3. Redisson 可重入锁的使用

3.1 引入 Redisson 依赖

在 Spring Boot 项目或其他 Java 项目中使用 Redisson,可以通过 Maven 引入 Redisson 的依赖:

<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.16.4</version>
</dependency>
3.2 配置 Redisson 客户端

Redisson 需要连接 Redis 服务器。可以通过 redisson.yaml 文件进行配置,或在代码中手动配置 Redis 连接。

使用 YAML 文件进行配置(redisson.yaml):

singleServerConfig:address: "redis://127.0.0.1:6379"password: nulldatabase: 0

在 Spring Boot 中加载该配置文件:

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;@Configuration
public class RedissonConfig {@Beanpublic RedissonClient redissonClient() {Config config = Config.fromYAML(RedissonConfig.class.getClassLoader().getResource("redisson.yaml"));return Redisson.create(config);}
}
3.3 使用 Redisson 实现可重入锁

一旦 Redisson 客户端配置好,就可以在代码中使用 Redisson 提供的分布式锁 API。下面是使用可重入锁的示例:

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.concurrent.TimeUnit;@Service
public class LockService {@Autowiredprivate RedissonClient redissonClient;public void executeWithLock() {// 获取分布式可重入锁RLock lock = redissonClient.getLock("myLock");try {// 尝试加锁,等待 10 秒,10 秒后自动释放if (lock.tryLock(10, 10, TimeUnit.SECONDS)) {try {// 执行业务逻辑System.out.println("业务逻辑执行中...");// 模拟内部调用方法,重入锁nestedLockMethod();} finally {// 释放锁lock.unlock();}}} catch (InterruptedException e) {e.printStackTrace();}}// 模拟重入锁的情况private void nestedLockMethod() {RLock lock = redissonClient.getLock("myLock");lock.lock();try {System.out.println("内部方法执行...");} finally {lock.unlock();}}
}

在上述代码中:

  • redissonClient.getLock("myLock") 获取一个可重入锁。
  • tryLock(10, 10, TimeUnit.SECONDS) 表示尝试获取锁,最多等待 10 秒,如果获取成功,锁将在 10 秒后自动释放。
  • nestedLockMethod() 方法中,模拟了重入锁的情况,同一个线程再次获取了同一个锁,而不会出现阻塞。
3.4 自动续期机制

Redisson 的分布式锁有一个非常重要的功能:自动续期。当一个线程获取了锁后,Redisson 会默认启动一个守护线程,为该锁的有效期进行续期,防止锁在执行长时间任务时被自动释放。

默认情况下,Redisson 会在锁被持有时每隔 30 秒续期,确保锁不会因为超时而被误释放。如果业务逻辑执行时间较长,这个功能可以防止锁过期失效。

自动续期的实现方式是,Redisson 在后台定期检查持有锁的线程是否仍然存活,如果线程仍在运行,它会延长锁的过期时间。

3.5 手动设置锁的超时时间

尽管 Redisson 提供了自动续期功能,但在某些场景下,开发者可能希望手动设置锁的有效时间。可以通过 lock() 方法的重载版本设置锁的超时时间:

// 设置锁的自动释放时间为 30 秒
lock.lock(30, TimeUnit.SECONDS);

这种方式适合业务逻辑执行时间较短且可以预估的场景。如果在设定的超时时间内没有释放锁,Redisson 会自动释放该锁。

4. Redisson 可重入锁的工作原理

4.1 Redis 中的锁实现

Redisson 的可重入锁是基于 Redis 的 SET 命令和 Lua 脚本实现的。当线程获取锁时,Redisson 会在 Redis 中执行类似如下的命令:

SET myLock <random-value> NX PX 10000
  • NX:表示只有当键不存在时才会设置,确保分布式锁的原子性。
  • PX:设置锁的有效期(过期时间),单位为毫秒。

可重入锁通过给每个线程生成一个唯一的标识(random-value)来区分不同线程的锁。如果同一个线程多次获取锁,Redisson 会使用计数器来跟踪锁的重入次数,释放锁时只会在计数器归零时才真正释放。

4.2 解锁的实现

解锁操作也需要保证线程安全,Redisson 通过 Lua 脚本确保只有持有锁的线程才能成功解锁。Lua 脚本可以保证解锁操作的原子性:

if redis.call("get", KEYS[1]) == ARGV[1] thenreturn redis.call("del", KEYS[1])
elsereturn 0
end

在解锁时,Redisson 会检查 Redis 中存储的锁标识是否与当前线程匹配,只有匹配时才会删除锁。

5. Redisson 可重入锁的应用场景

可重入锁在以下场景中非常有用:

  • 分布式资源争用:多个服务实例或线程同时访问共享资源,如数据库、文件系统、第三方服务等,使用分布式锁可以确保这些资源不会被并发修改。
  • 任务调度和执行:在分布式任务调度系统中,确保同一时间只有一个实例在处理某个任务,防止任务重复执行。
  • 库存管理和订单处理:在电商系统中,避免多个请求同时操作同一件商品的库存,导致超卖问题。

6. 注意事项

  • 锁的自动续期:Redisson 默认的自动续期功能适合大部分场景,但开发者应确保持有锁的业务逻辑不会意外地被卡住或进入死循环。
  • 合理设置超时时间:在使用 tryLock() 或手动设置锁的超时时间时,应根据业务需求合理设置,避免锁的有效期太长或太短。
  • 持久化与高可用:确保 Redis 服务器的高可用性,Redisson 锁依赖 Redis 的可靠性,建议使用 Redis 集群或主从架构。

7.

总结

Redisson 为 Java 开发者提供了强大的分布式锁功能,特别是可重入锁的实现,使得在分布式系统中可以轻松实现线程间和服务实例间的资源竞争控制。通过 Redisson 的可重入锁,开发者可以确保同一线程在获取锁后能够多次进入锁定区域,避免死锁。同时,Redisson 的自动续期功能确保了锁在长时间任务中的可靠性。配合 Redis 的高性能和高可用性,Redisson 是分布式环境中实现锁机制的理想选择。


http://www.ppmy.cn/news/1524268.html

相关文章

化工原料环保能源网站模板整站打包下载

图片在最下面 响应式新能源化工研究院网站模板.zip 营销型硅胶制品原料网站模板.zip 环境水务治理网站模板.zip 响应式新能源清洁能源公司网站模板.zip 环保废气废水处理工程类网站模板.zip 活性炭净化炭企业网站模板.zip 响应式新能源开发企业网站模板.zip 营销型塑料…

Docker 镜像的发布过程

搭建了一个镜像后&#xff08;例如搭建好了一个开发环境&#xff09;&#xff0c;如果想要供其他人使用&#xff0c;此时就可以发布镜像到镜像仓库。 本文就试着将本地的镜像&#xff0c;发布到阿里云。 ‍ 发布流程 ‍ 示意图&#xff1a; ​ ‍ 首先 Images 可以由容…

数据结构之栈和队列的应用

目录 一、栈的应用 1. 括号匹配 2. 计算后缀表达式 方法一&#xff08;栈&#xff09; 方法二&#xff08;数组模拟栈&#xff09; 二、队列应用 1. 二叉树层序遍历 方法一&#xff08;队列&#xff09; 三、总结 一、栈的应用 1. 括号匹配 给定一个只包括 (&#xf…

JS_事件的简介和常见事件的绑定_01

HTML事件可以是浏览器行为&#xff0c;也可以是用户行为。当这些行为发生时&#xff0c;可以自动触发对应的JS函数的运行&#xff0c;我们称之为事件发生&#xff0c;JS的事件驱动指的就是行为触发代码运行的这种特点 一、事件的绑定方式 通过元素的属性绑定 on***通过DOM编程…

【LeetCode每日一题】——912.排序数组

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 优先队列 二【题目难度】 中等 三【题目编号】 912.排序数组 四【题目描述】 给你一个整数…

PVE虚拟机搭建K8s集群

PVE虚拟机搭建K8s集群 创建虚拟机 选择 pve3节点安装虚拟机&#xff0c;此节点的内网网段为 172.110.0.0&#xff0c;在不同的局域网段 选择本地提供的镜像 存储页磁盘总线选择SATA&#xff0c;存储选择HDD卷 Master 节点设置的CPU数量为16&#xff08;不能超过20&#xff0…

C++ IO流全解析:标准库中的数据处理与文件读写艺术

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;C从入门到精通 目录 一&#xff1a; &#x1f525; C语言的输入与输出 二&#xff1a; &#x1f525; 流是什么 三&#xff1a; &#x1f525; CIO流&#x1f680; 3.1 C标准IO流&#x1f680; ist…

超详细!!!electron-vite-vue开发桌面应用之创建新窗口以及主进程和子进程的通信监听(十二)

云风网 云风笔记 云风知识库 一、新建打开窗口 1、在electron/main.ts中加入主进程打开窗口逻辑代码 import { ipcMain } from "electron"; ipcMain.handle("open-win", (_, arg) > {const childWindow new BrowserWindow({webPreferences: {preloa…

9.11练习

TCP使用多线程实现多用户通信 #include<myhead.h> #define SERPORT 8888 #define SERIP "192.168.0.143" #define BACKLOG 10 typedef struct {int newfd;//储存新的文件描述符struct sockaddr_in cin;//储存客户端信息 }SIG; void *accept_newcli(void *sig…

如何保证 UDP 的可靠性传输?

一、TCP 和 UDP 的区别 1、TCP基于连接&#xff0c;UDP基于无连接。 2、对系统资源的要求&#xff1a;TCP 较多&#xff0c;UDP 少。 3、UDP 程序结构较简单。 4、TCP基于流模式&#xff0c;UDP基于数据报模式 。 5、TCP 保证数据正确性&#xff0c;UDP 不保证数据准确性&…

sqlite在Windows环境下安装、使用、node.js连接

sqlite在Windows环境下安装、使用、node.js连接 前言&#xff1a;2024年9月10日 1. 下载安装 sqlite 的安装非常简单 去官网下载对应压缩包 将两个压缩包解压&#xff0c;并将解压出来的文件放在同一目录下 将上面的目录路径配置到环境变量 path 中 2. 执行 sql sqlite …

Ae软件2018-2023全版本 不限速下载

Ae软件2018-2023全版本 不限速下载 Adobe After Effects 2018-2023全版本不限速下载指南 Adobe After Effects&#xff08;简称Ae&#xff09;是一款由Adobe公司开发的业界领先的视觉效果和动态图形设计软件。自2018年以来&#xff0c;Ae不断推出新版本&#xff0c;每个版本都…

C++ 封装 DLL 供 Unity 调用

一&#xff1a;封装DLL 开发工具最好使用 Visual Studio 20XX 来制作&#xff0c;因为VS Code 需要配置很多东西&#xff0c;环境搭建过程比较复杂。 a、我安装的是 Visual Studio 2022&#xff0c;安装的时候&#xff0c;【工作负荷】记得勾选 【使用C的桌面开发】和【使用C的…

【华为笔试2】

华为笔试2 一、模拟1、2024.05.08-暑期实习-第一题-塔子哥的汇编作业1、2024.05.08-暑期实习-第二题-塔子哥的计网实验2.输入输出3.问题总结python 一、模拟 1、2024.05.08-暑期实习-第一题-塔子哥的汇编作业 2024.05.08-暑期实习-第一题-塔子哥的汇编作业 import sys def …

DIC技术助力新能源汽车主机厂力学测试研发与整车性能提升

在新能源汽车研发过程中&#xff0c;非接触式全视场应变DIC测量方案&#xff0c;越来越受到汽车主机厂的信赖与认可。传统接触式传感器&#xff0c;在精度、灵活性和数据处理能力上存在局限。DIC技术可提供精确、高效、全视场、便捷的非接触式测量解决方案。 在汽车研发阶段&a…

什么是场外个股期权?场外个股期权怎么参与交易?

今天期权懂带你了解什么是场外个股期权&#xff1f;场外个股期权怎么参与交易&#xff1f;场外个股期权是一种在开放市场上&#xff0c;由交易双方直接协商进行的期权交易&#xff0c;具有高度的定制化和灵活性&#xff0c;但也伴随较高的交易对手风险和流动性风险。 什么是场…

计算字符串的自定义长度、自定义进制随机均匀短散列值

要生成自定义长度、自定义进制的随机均匀短散列值&#xff0c;可以结合哈希函数和进制转换来实现。哈希函数可以将字符串映射为固定长度的二进制值&#xff0c;然后根据自定义的进制进行编码&#xff0c;生成你需要的短散列值。我们可以使用 PHP 来实现该功能&#xff0c;以下是…

turtle.circle() 函数绘制弧形规律助记图 ← Python

【Python 之 turtle.circle() 函数定义】 定义&#xff1a;turtle.circle(radius, extent)作用&#xff1a;根据半径 radius 绘制 extent 角度的弧形参数&#xff1a;radius &#xff1a;弧形半径当 radius 值为正数时&#xff0c;圆心在当前位置/小海龟左侧。当 radius 值为负…

神经网络通俗理解学习笔记(1)

神经网络通俗理解学习笔记&#xff08;1&#xff09; 神经网络原理激活函数前向传播和反向传播多层感知机代码实现加载数据网络结构损失函数优化器训练测试保存 回归问题一元线性回归多元线性回归多项式回归 线性回归代码实现数据生成设置超参数初始化参数可视化Pytorch模型实现…

22_图论中的高级数据结构

菜鸟&#xff1a;老鸟&#xff0c;我最近在处理一个网络节点数据的问题&#xff0c;发现代码运行得特别慢。你能帮我看看有什么优化的方法吗&#xff1f; 老鸟&#xff1a;当然可以。你处理的是图结构对吗&#xff1f;你是如何存储和操作这些节点的&#xff1f; 菜鸟&#xf…