什么是Redission可重入锁,其实现原理是什么?

news2024/11/24 4:02:49

一、概述

Redission是一个可重入锁,它可以在分布式系统中用于实现互斥锁。这种锁可以允许多个线程同时获取锁,但在任何给定时间只有一个线程可以执行受保护的代码块。

Redission锁提供了一种简单的方法来保证在分布式系统中的互斥性,同时支持可重入性。这意味着一个线程可以在获取锁之后再次获取同一个锁,而不需要等待锁释放。

  • Redission锁使用lua脚本来实现加锁和解锁操作。当一个线程想要获取锁时,它会发送一个lua脚本到redis服务器。这个脚本首先会检查当前时间是否比之前获取锁的时间早,如果不是,则脚本会返回一个错误。否则,它会将当前线程的id添加到一个列表中,表示该线程已经获取了锁。如果锁没有被其他线程持有,那么当前线程就可以执行受保护的代码块了。
     
  • 当一个线程完成执行受保护的代码块时,它需要发送一个lua脚本到redis服务器来解锁。这个脚本会检查当前线程是否持有锁,如果是,则它将从列表中删除当前线程的id并返回成功。否则,脚本会返回一个错误。

Redission锁还支持超时设置,这意味着锁只能在一定的时间内有效。当锁超时后,其他线程就可以获取锁并执行受保护的代码块了。

Redission是一个高性能的锁实现,它被广泛用于分布式系统中的互斥操作。它可以与多种语言和框架集成,包括Java、C++、Python和Ruby等。

二、原理

在Lock锁中,他是借助于底层的一个voaltile的一个state变量来记录重入的状态的,比如当前没有人持有这把锁,那么state=0,假如有人持有这把锁,那么state=1,如果持有这把锁的人再次持有这把锁,那么state就会+1 ,如果是对于synchronized而言,他在c语言代码中会有一个count,原理和state类似,也是重入一次就加一,释放一次就-1 ,直到减少成0 时,表示当前这把锁没有被人持有。

在redission中,我们的也支持支持可重入锁

在分布式锁中,他采用hash结构用来存储锁,其中大key表示表示这把锁是否存在,用小key表示当前这把锁被哪个线程持有,所以接下来我们一起分析一下当前的这个lua表达式

这个地方一共有3个参数

KEYS[1] : 锁名称

ARGV[1]: 锁失效时间

ARGV[2]: id + “:” + threadId; 锁的小key

exists: 判断数据是否存在 name:是lock是否存在,如果==0,就表示当前这把锁不存在

redis.call(‘hset’, KEYS[1], ARGV[2], 1);此时他就开始往redis里边去写数据 ,写成一个hash结构

Lock{id + **":"** + threadId :  1

}

如果当前这把锁存在,则第一个条件不满足,再判断

redis.call('hexists', KEYS[1], ARGV[2]) == 1

此时需要通过大key+小key判断当前这把锁是否是属于自己的,如果是自己的,则进行

redis.call('hincrby', KEYS[1], ARGV[2], 1)

将当前这个锁的value进行+1 ,redis.call(‘pexpire’, KEYS[1], ARGV[1]); 然后再对其设置过期时间,如果以上两个条件都不满足,则表示当前这把锁抢锁失败,最后返回pttl,即为当前这把锁的失效时间

如果小伙帮们看了前边的源码, 你会发现他会去判断当前这个方法的返回值是否为null,如果是null,则对应则前两个if对应的条件,退出抢锁逻辑,如果返回的不是null,即走了第三个分支,在源码处会进行while(true)的自旋抢锁。

  • 添加锁脚本
"if (redis.call('exists', KEYS[1]) == 0) then " +
     "redis.call('hset', KEYS[1], ARGV[2], 1); " +
     "redis.call('pexpire', KEYS[1], ARGV[1]); " +
     "return nil; " +
 "end; " +
 "if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
     "redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
     "redis.call('pexpire', KEYS[1], ARGV[1]); " +
     "return nil; " +
 "end; " +
 "return redis.call('pttl', KEYS[1]);"
  • 删除锁Lua脚本
if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then
    return nil;
end ;
local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1);
if (counter > 0) then
    redis.call('pexpire', KEYS[1], ARGV[2]);
    return 0;
else
    redis.call('del', KEYS[1]);
    redis.call('publish', KEYS[2], ARGV[1]);
    return 1;
end ;
return nil;

三、流程图

在这里插入图片描述

四、示例

@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class RedissonTest {

    @Resource
    private RedissonClient redissonClient;

    private RLock rLock;

    @BeforeEach
    public void setUp() {
        rLock = redissonClient.getLock("order");
    }


    @Test
    public void method1() {
        boolean isLock = rLock.tryLock();
        if (isLock) {
            log.error("获取锁失败.....1");
            return;
        }
        try {
            log.info("获取锁成功....1");
            method2();
            log.info("开始执行业务....1");
        } finally {
            log.info("释放锁....1");
            rLock.unlock();
        }
    }

    public void method2() {
        boolean isLock = rLock.tryLock();
        if (isLock) {
            log.error("获取锁失败.....2");
            return;
        }
        try {
            log.info("获取锁成功....2");
            log.info("开始执行业务....2");
        } finally {
            log.info("释放锁....2");
            rLock.unlock();
        }
    }   
}

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

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

相关文章

chatgpt赋能python:Python中的父类方法和super函数

Python中的父类方法和super函数 在Python中,我们经常会涉及到继承父类的方法和属性。当我们在子类中重写一个父类方法时,有时我们需要在子类方法中访问父类方法,可以使用Python的内置函数super()来实现。 什么是父类方法 在面向对象编程中…

runway gen2

来自Runway文生成视频ai大模型Gen-2_哔哩哔哩_bilibili来自Runway文生成视频ai大模型Gen-2,距离视频制作自由又近了一步。, 视频播放量 1651、弹幕量 0、点赞数 21、投硬币枚数 2、收藏人数 42、转发人数 22, 视频作者 旭升说, 作者简介 一起聊下互联网的那些事&…

10大白帽黑客专用的 Linux 操作系统

平时在影视里见到的黑客都是一顿操作猛如虎,到底他们用的都是啥系统呢? 今天给大家分享十个白帽黑客专用的Linux操作系统。 ▍1. Kali Linux Kali Linux是最著名的Linux发行版,用于道德黑客和渗透测试。Kali Linux由Offensive Security开发&…

[k8s]Kubernetes简介

文章目录 Kubernetes介绍术语Label StatefulSet 存储类VolumePersistent Volume IP地址Node IPPod IPService Cluster IPExternal IP PodPod定义Pod生命周期与重启策略NodeSelector(定向调度)NodeAffinity(亲和性调度)PodAffinity…

164. 最大间距

题目描述&#xff1a; 主要思路&#xff1a; 利用桶排序的思路&#xff0c;取最大最小值的差值/个数&#xff0c;答案一定是大于等于这个数的&#xff0c;每个块为一个桶&#xff0c;维护这个桶内的最大最小值。 class Solution { public:int maximumGap(vector<int>&a…

【软件开发】Redis 理论篇(一)

Redis 理论篇&#xff08;一&#xff09; 一、概述 1.什么是 Redis&#xff1f; Redis 是一个使用 C 语言写成的&#xff0c;开源的高性能 Key-Value 非关系缓存数据库。它支持存储的 Value 类型相对更多&#xff0c;包括 string&#xff08;字符串&#xff09;、list&#x…

MyBatis基本操作及SpringBoot单元测试

目录 一、什么是单元测试&#xff1f; 1.1 单元测试的好处 1.2 单元测试的实现步骤 1.2.1 生成单元测试类&#xff1a; 1.2.2 SpringBootTest注解 1.2.3 检验方法结果&#xff1a; 二、利用MyBatis实现查询操作 2.1单表查询 2.2 参数占位符 #{} 和 ${} 2.2.1 ${} 字符…

全网最细,Selenium自动化测试项目实战技巧,从0到1精通自动化测试...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Selenium4自动化测…

重学Ajax

概述 Ajax&#xff08;Asynchronous JavaScript And XML&#xff09;即异步 JavaScript 和 XML&#xff0c;是一组用于在网页上进行异步数据交换的Web开发技术&#xff0c;可以在不刷新整个页面的情况下向服务器发起请求并获取数据&#xff0c;然后将数据插入到网页中的某个位置…

【Docker】Swarm学习

文章目录 什么是Docker Swarm定义与Docker Compose对比 基本结构图关键概念工作模式NodeService任务与调度服务副本与全局服务 Swarm的调度策略Swarm的特性批量创建服务强大的集群的容错性服务节点的可扩展性调度机制 集群部署基础架构准备工作创建Swarm并添加节点在Swarm中部署…

测试进阶篇

✏️作者&#xff1a;银河罐头 &#x1f4cb;系列专栏&#xff1a;JavaEE &#x1f332;“种一棵树最好的时间是十年前&#xff0c;其次是现在” 目录 按照对象划分界面测试可靠性测试容错性测试文档测试兼容性测试易用性测试安装卸载测试安全测试性能测试内存泄漏测试 按是否查…

老板让你Excel统计数据无从下手?没事,ChatGPT来帮你!

系列文章目录 老板让你写个PPT没有头绪&#xff1f;没事&#xff0c;ChatGPT来帮你&#xff01;传送门 文章目录 系列文章目录前言一、不会公式&#xff1f;帮你生成二、不会处理数据&#xff1f;帮你处理写在最后 前言 自从人工智能横空而出&#xff0c;它在人们的生活中产生…

如何在华为OD机试中获得满分?Java实现【 第一个错误的版本】一文详解!

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: Java华为OD机试真题&#xff08;2022&2023) 文章目录 1. 题目描述2. 输入描述3. 输出描述…

【P36】JMeter 交替控制器(Interleave Controller)

文章目录 一、交替控制器&#xff08;Interleave Controller&#xff09;参数说明二、测试计划设计 一、交替控制器&#xff08;Interleave Controller&#xff09;参数说明 可以将内部的组件在线程迭代时交替执行&#xff1b;交替控制器内部一般会有多个取样器 选择线程组右…

6.6.4 PCS创建Oracle 资源及资源组

在RHCS体系中&#xff0c;Oracle的启动是按以下顺序进行的&#xff1a; VIP。监听器。逻辑卷&#xff08;ISCSI共享出来的&#xff09;。文件系统&#xff08;在逻辑卷上创建&#xff09;。数据库实例。 上边这些资源&#xff0c;在PCS里创建好以后&#xff0c;将其组合成一个…

接口自动化一键集成,Jenkins持续集成Allure报告!

目录 前言&#xff1a; 一、接口测试框架选型 二、接口自动化框架封装的设计 2.1 创建测试用例 2.2 执行测试用例 2.3 生成测试报告 三、 实现Jenkins持续集成 3.1 安装Jenkins 3.2 配置Jenkins 3.3 创建Jenkins任务 四、总结 前言&#xff1a; 接口测试作为软件测试中的…

chatgpt赋能python:Python程序中断

Python 程序中断 Python 是一种高级编程语言&#xff0c;被广泛应用于数据科学和机器学习等领域。但是&#xff0c;有时候我们需要中断 Python 程序的执行&#xff0c;以便处理意外事件或者出现错误时进行调试。在这篇文章中&#xff0c;我们将探讨 Python 程序中断的各种方法…

Rocky9-Linux上安装KVM虚拟机

一、案例环境 使用一台物理机器,安装Rocky9-Linux的64位系统,test01是在宿主机kvm中安装的虚拟机 主机 操作系统 IP地址 主要软件 kvm Centos 7 192.168.100.46 KVM test01 Centos 7 192.168.100.32 虚拟机

梅须逊雪三分白,雪却输梅一段香——CSS动画与JavaScript动画

CSS动画并不是绝对比JavaScript动画性能更优越&#xff0c;开源动画库Velocity.js等就展现了强劲的性能。 一、两者的主要区别 先开门见山的说说两者之间的区别。 1&#xff09;CSS动画&#xff1a; 基于CSS的动画一般由浏览器“主线程”之外的独立线程处理&#xff0c;在其…

SpringBoot2-核心技术(一)

SpringBoot2-核心技术&#xff08;一&#xff09; 了解SpringBoot配置文件的使用 文章目录 SpringBoot2-核心技术&#xff08;一&#xff09;了解SpringBoot配置文件的使用一、文件类型1. properties2. yaml 二、yaml的基本使用1. 基本语法2. 数据类型2.1 字面量 2.2 对象2.3 …