分布式锁-Redisson 可重入锁

news2024/9/17 8:57:31

在分布式系统中,分布式锁是一种常用的机制,用来在多个实例或服务之间控制共享资源的访问,确保不会出现并发冲突或资源竞争。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: null
  database: 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 {

    @Bean
    public 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 {

    @Autowired
    private 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] then
    return redis.call("del", KEYS[1])
else
    return 0
end

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

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

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

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

6. 注意事项

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

7.

总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2117053.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

冒泡排序算法介绍

冒泡排序算法介绍 如果真的累了&#xff0c;就拉上窗帘关上手机关掉闹钟深呼吸一口气钻进被窝&#xff0c;好好地睡一觉&#xff0c;难熬的日子总需要一些温暖&#xff0c;而什么都不如被窝的温暖来的踏实。 冒泡排序是一种经典的排序算法&#xff0c;它通过重复遍历待排序的序…

如何恢复回收站中已删除/清空的文件

回收站清空后如何恢复已删除的文件&#xff1f;是否可以恢复永久删除的文件&#xff1f;或者最糟糕的是&#xff0c;如果文件直接被删除怎么办&#xff1f;本文将向您展示清空回收站后恢复已删除数据的最佳方法。 回收站清空后如何恢复已删除的文件&#xff1f; “回收站清空后…

从零开始搭建GPU深度学习环境(pytorch)

傻乎乎的我&#xff0c;突然发现我自己的笔记本电脑居然有gpu&#xff0c;这个电脑是我弟在2017年购入的。 电脑已经按照了cpu环境&#xff0c;现在增加gpu环境 参考torch的cpu版本和gpu版本有什么区别 torch与cuda版本_mob64ca13f6035c的技术博客_51CTO博客 前言&#xff1a…

Vue3使用Uni-ui的popup弹出层组件

由于uni-ui中有些组件文档的基于vue2编写的&#xff0c;比如popup组件 下面是vue3的写法 除了文档中要求的aleterDialog外&#xff0c;还得利用v-if设置一个isDialog判断 // template // script 解决

数学建模笔记——TOPSIS[优劣解距离]法

数学建模笔记——TOPSIS[优劣解距离法] TOPSIS(优劣解距离)法1. 基本概念2. 模型原理3. 基本步骤4. 典型例题4.1 矩阵正向化4.2 正向矩阵标准化4.3 计算得分并归一化4.4 python代码实现 TOPSIS(优劣解距离)法 1. 基本概念 C. L.Hwang和 K.Yoon于1981年首次提出 TOPSIS(Techni…

【Linux网络】详解TCP协议(1)

&#x1f389;博主首页&#xff1a; 有趣的中国人 &#x1f389;专栏首页&#xff1a; Linux网络 &#x1f389;其它专栏&#xff1a; C初阶 | C进阶 | 初阶数据结构 小伙伴们大家好&#xff0c;本片文章将会讲解 TCP协议 的相关内容。 如果看到最后您觉得这篇文章写得不错&am…

力扣每日一题 有序数组的平方 双指针 逆向思维

Problem: 977. 有序数组的平方 &#x1f468;‍&#x1f3eb; 灵神题解 class Solution {public int[] sortedSquares(int[] nums) {int n nums.length;int [] ans new int[n];int p n-1;int i 0;int j n-1;while(p > 0){int x nums[i] * nums[i];int y nums[j] * n…

结构体小知识

目录 前言1.结构体数组1.1结构体数组理解1.2结构体数组知识运用1.3 -> 操作符 2. 知识拓展 前言 本期blog是对上一期指针知识的知识补充&#xff0c;如果各位大佬感兴趣的话&#xff0c;可以结合起来一起看&#xff01; 1.结构体数组 1.1结构体数组理解 结构体数组在本…

关系的规范化与范式详解

在数据库设计中&#xff0c;关系的规范化是确保数据结构合理性、减少冗余和异常的关键步骤。如果你是一个数据库设计的初学者&#xff0c;这篇文章将为你深入浅出地讲解 关系规范化 和 范式 的核心概念&#xff0c;并通过简洁的示例帮助你加深理解。 关系的规范化&#xff1a;…

JavaScript进阶day1

目录 1.作用域 1.1 局部作用域 1.2 全局作用域 1.3 作用域链 1.4 JS垃圾回收机制 1.4.1 什么是垃圾回收机制&#xff1f; 1.4.2 内存的生命周期 1.4.3 算法说明 1.5 闭包 1.6 变量提升 2.函数进阶 2.1 函数提升 2.2 函数参数 2.2.1 动态参数 2.2.2 剩余参数 2.…

GB2312编码(加2020H、8080H原理)

区位码、内码、国标码 转换及原理 背景答题思考相关资料 背景 问题: 某汉字的国标码为5650H&#xff0c;那么它的机内码为&#xff08; B &#xff09;。A E6E0H B D6D0H C C6C0H D 8080H答题 思考 为什么要加上2020H和8080H&#xff1f;区位码、内码、国标码怎么转换非常简单…

【硬件知识】关于RAM的“那些事”

文章目录 一、DRAM&#xff08;动态随机存取存储器&#xff09;二、SRAM&#xff08;静态随机存取存储器&#xff09;三、DRAM和SRAM的差异与区别 一、DRAM&#xff08;动态随机存取存储器&#xff09; 工作原理&#xff1a;DRAM使用电容来存储数据。每一位数据通过一个电容和…

【深度学习讲解笔记】第1章-机器学习基础

1.机器学习是什么 机器学习&#xff08;Machine Learning&#xff0c;ML&#xff09;&#xff0c;顾名思义就是让机器学会做一件事情&#xff0c;比如语音识别&#xff0c;机器听一段声音&#xff0c;产生这段声音对应的文字。或是识别图片中有几个人&#xff0c;几辆车。这些…

2024年语音识别转文字工具的崛起

无论是繁忙的会议记录、远程教学的即时笔记&#xff0c;还是日常生活的语音备忘&#xff0c;只需轻轻一说&#xff0c;便能瞬间转化为清晰可编辑的文字&#xff0c;这种便捷与高效无疑为现代生活增添了无限可能。本文将带你深入探索语音识别转文字工具的奥秘。 1.365在线转文字…

【Python篇】matplotlib超详细教程-由入门到精通(上篇)

文章目录 第一部分&#xff1a;基础概念与简单绘图1.1 matplotlib 简介1.2 创建第一个折线图1.3 图表的基本组成元素 第二部分&#xff1a;图表样式与修饰2.1 修改图表样式2.2 添加图例2.3 调整坐标轴与刻度 第三部分&#xff1a;绘制不同类型的图表3.1 散点图 (Scatter Plot)3…

使用 Homebrew 在 macOS 上安装 Conda

Homebrew 是一个流行的 macOS 包管理器&#xff0c;可以帮助你安装和管理各种软件包。 以下是使用 Homebrew 安装 Conda 的步骤&#xff1a; 1. 安装 Homebrew 如果你还没有安装 Homebrew&#xff0c;可以通过以下命令安装&#xff1a; /bin/bash -c "$(curl -fsSL htt…

《机器学习》—— XGBoost(xgb.XGBClassifier) 分类器

文章目录 一、XGBoost 分类器的介绍二、XGBoost&#xff08;xgb.XGBClassifier&#xff09; 分类器与随机森林分类器&#xff08;RandomForestClassifier&#xff09;的区别三、XGBoost&#xff08;xgb.XGBClassifier&#xff09; 分类器代码使用示例 一、XGBoost 分类器的介绍…

微信小程序 自定义组件

1. 微信小程序 自定义组件 微信小程序支持组件化开发&#xff0c;这有助于我们复用代码&#xff0c;提高开发效率。下面我将给出一个简单的微信小程序组件化示例&#xff0c;包括一个自定义组件的创建和使用。 1.1. 创建自定义组件 首先&#xff0c;在项目的 components 目录…

建筑二次供水的基本概念

什么是二次供水&#xff1f; 二次供水是城市供水的主要组成部分&#xff0c;是指集中式供水在入户之前经再度储存、加压和消毒后&#xff0c;通过管道输送给用户的供水方式。 为什么要使用二次供水&#xff1f; 由于市政供水的服务水压通常只能达到较低的楼层&#xff0c;而…

部分库函数及其模拟

前言&#xff1a;当我们学习c/c库函数的时候&#xff0c;我们可以用网站 cplusplus.com - The C Resources Network 来进行查阅&#xff0c;学习。 目录 库函数&#xff1a; 1.字符串函数 1.1求字符串长度 strlen 1.2长度不受限制的字符串函数 1.2.1strcpy 1.2.2strca…