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

一、概述

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();
        }
    }   
}

运行结果:

com.koo.RedissonTest                     : 获取锁成功....1
com.koo.RedissonTest                     : 获取锁成功....2
com.koo.RedissonTest                     : 开始执行业务....2
com.koo.RedissonTest                     : 释放锁....2
com.koo.RedissonTest                     : 释放锁....1

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

K8s in Action 阅读笔记——【5】Services: enabling clients to discover and talk to pods

K8s in Action 阅读笔记——【5】Services: enabling clients to discover and talk to pods 你已了解Pod以及如何通过ReplicaSets等资源部署它们以确保持续运行。虽然某些Pod可以独立完成工作,但现今许多应用程序需要响应外部请求。例如,在微服务的情况…

day42_jsp

今日内容 零、 复习昨日 一、JSP 二、EL 三、JSTL 四、MVC 零、 复习昨日 一、JSP 1.0 引言 现有问题 在之前学习Servlet时,服务端通过Servlet响应客户端页面,有什么不足之处? 开发方式麻烦:继承父类、覆盖方法、配置Web.xml或注…

【Proteus仿真】51单片机+步进电机驱动

【Proteus仿真】51单片机步进电机驱动 🔖Proteus仿真基础实验-步进电机驱动🌿Proteus8.12平台 📋步进电机简介 步进电机是一种将电脉冲转换为角位移的开环控制元步进电机。一般地,当步进驱动器接收到脉冲信号时,它将根…

【工作流】Activiti工作流简介以及Spring Boot 集成 Activiti7

文章目录 前言一、activiti介绍二、工作流引擎三、BPMN四、数据库五、Spring Boot 集成 Activiti7安装插件引入依赖配置文件 总结 前言 什么是工作流? 工作流指通过计算机对业务流程进行自动化管理,实现多个参与者按照预定义的流程去自动执行业务流程。 …

Linux :: vim 编辑器:详解:文本复制/粘贴/剪切/删除 与 撤销普通操作及撤销撤销操作

前言:本篇是 Linux 基本操作篇章的内容! 笔者使用的环境是基于腾讯云服务器:CentOS 7.6 64bit。 学习集: C 入门到入土!!!学习合集Linux 从命令到网络再到内核!学习合集 前文&#x…

【哈希】位图/布隆过滤器

位图 前言 在实现位图结构之前我们先看一个问题: 给出40亿个不重复的无符号整型,并且是无序的。然后给一个无符号整数,怎样快速判断这个数是否在40亿个数之中。 方法一:对40亿个数据进行遍历。我们会发现,时间复杂度…

使用kotlin用回溯法解决电话号码的字母组合问题

17. 电话号码的字母组合 难度中等 2474 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 示例 1: 输入&#…

C++const函数的运用:深度解析const函数的魅力

C 深度解析const函数的魅力 1. C const函数的基本概念(Basic Concepts of const Functions in C)1.1 const函数的定义与特性(Definition and Characteristics of const Functions)1.2 const函数的使用场景(Usage Scena…

Spring(四)基于xml的自动装配

自动装配:根据指定的策略,在IOC容器中匹配某一个bean,自动为指定的bean中所依赖的类类型或接口类型属性赋值。 首先我们来熟悉三层架构的创建过程: 三层架构为controller层,service层,dao层。 在service层里面创建ser…

php内置类小结

文章目录 php内置类小结Error、Exception进行xss、绕过hash比较Error类Exception类使用Error、Exception内置类绕过md5、sha1等哈希比较Error类详解Exception类详解例题:[2020 极客大挑战]Greatphp 使用DirectaryIterator、Filesystemlterator、Globlterator内置类读…

为什么要“内卷”创始人?如何内卷?

受疫情影响,近几年各个行业都受到很大的冲击,同时有许多知识创业者反而逆势增长,这是为什么呢?因为有一个好的领导者!一家企业的发展,和创始人的心力和决心紧密联系着,只有好的将军才能带领出好…

如何解决航空企业数字化转型中的痛点?

数字化时代,越来越多的企业开始关注数字技术,希望通过数字化改造提高企业效率和竞争力,为企业创造更多的商机和利润。今天就来同大家探讨航空领域,小程序在企业数字化转型中发挥的作用、 航空业员工端App的敏捷转型挑战 技术上的…

资源配额(ResourceQuota) 资源限制(LimitRange)

资源配额 ResourceQuota 资源配额 ResourceQuota:限制命名空间总容量。 当多个团队、多个用户共享使用K8s集群时,会出现不均匀资源使用,默认情况下先到先得,这时可以通过ResourceQuota来对命名空间资源使用总量做限制,…

Aerial Vision-and-Dialog Navigation阅读报告

Aerial Vision-and-Dialog Navigation 本次报告,包含以下部分:1摘要,2数据集/模拟器,3AVDN任务,4模型,5实验结果。重点介绍第2/3部分相关主页:Aerial Vision-and-Dialog Navigation (google.com…

基于C#的串口扫描枪通信实战

今天搞大事,观众们动起来,搞事的目的是 掌握串口通信及winform开发技术 硬件设备:1、串口激光扫描枪,注意是串口,不是USB口 2、USB转串口的连接线一根,如图连接所示 3、USB扩展器一个,如果你电…

iphone苹果手机如何备份整个手机数据?

手机上的数据变得越来越重要,大家也越来越注重数据安全。如果手机设备丢失的话,不仅是设备的丢失,还是数据的丢失。因此,备份数据就显得很重要。那么,iphone如何备份整个手机,苹果怎么查备份的照片&#xf…

Python量化交易:策略创建运行流程

学习目标 目标 知道策略的创建和运行知道策略的相关设置知道RQ的策略运行流程应用 无 1、体验创建策略、运行策略流程 1.1 创建策略 1.2 策略界面 2、 策略界面功能、运行介绍 2.1 一个完整的策略需要做的事情 选择策略的运行信息: 选择运行区间和初始资金选择回…

笔记本安装CentOS

目标: 1.利用闲置笔记本 2.省电/提高利用率/不安装图形桌面/最小化安装/附加选项:开发工具 step1:镜像下载 CentOS-7.9 163镜像 阿里云镜像 清华大学镜像 随便选一个 step2: 下载U盘系统盘制作工具Rufus U盘写入镜像/安装 step3: 安装完毕进入系统 …

【Linux】文件的压缩和解压

欢迎来到博主 Apeiron 的博客,祝您旅程愉快 ! 时止则止,时行则行。动静不失其时,其道光明。 目录 1、压缩格式 2、压缩软件 3、tar 命令简介 4、tar 命令压缩 5、总结 1、压缩格式 在市面上有非常多的压缩格式,…

《面试1v1》类加载过程

我是 javapub,一名 Markdown 程序员从👨‍💻,八股文种子选手。 面试官: 你了解Java的类加载过程吗?跟我聊聊classes是如何加载到JVM中的。 候选人: Java的类加载过程由加载、验证、准备、解析和初始化5个…