Redisson可重入锁原理

微信公众号访问地址:Redisson可重入锁原理

推荐文章:

    1、使用原生Redis命令实现分布式锁

​    2、为什么引入Redisson分布式锁?

    3、SpringBoot整合多数据源,并支持动态新增与切换(详细教程)

    4、SpringBoot统一标准响应格式及异常处理

   5、SpringBoot用线程池ThreadPoolTaskExecutor异步处理百万级数据

一、Redisson可重入锁原理

    1、可重入:利用hash结构记录线程id和重入次数。

    2、可重试:利用信号量和PubSub功能实现等待、唤醒,获取

锁失败的重试机制。

    3、超时续约:利用watchDog,每隔一段时间(releaseTime

/3),重置超时时间。

      Redisson提供的分布式锁是可重入的,它使用的是Hset命令和Hash数据结构。

      调用redisson.lock()方法会在redis中存储一个hash数据结构,key为锁的名称,value中的field为当前操作的线程id,value为锁重入的次数。

代码测试:

private  RLock rLock=null;    @ApiOperation(value="测试分布式锁的可重入锁原理", notes="testRedisson02")    @GetMapping("/testRedisson02")    public String testRedisson02() throws InterruptedException {        //1、获取锁(可重入),并指定锁的名称        rLock=redissonClient.getLock("lock:testRedisson02");        //2、尝试获取锁,参数分别是:waitTime:获取锁的最大等待时间(期间会重试)        // leaseTime:锁自动释放时间  TimeUnit:时间单位        //tryLock(long waitTime, long leaseTime, TimeUnit unit)        boolean isLock=rLock.tryLock(1,100, TimeUnit.SECONDS);        //3、判断锁获取成功及释放        if(isLock){            try {                log.info("执行正常的业务02......");                this.testRedisson03();            }catch (Exception e){                log.info("锁获取异常02e:"+e);            }finally {                //锁未关闭,则手动释放锁                if(rLock.isLocked()){                    rLock.unlock();                    log.info("释放锁成功02");                }            }        }        return "true";    }
    public void testRedisson03() throws InterruptedException {        //2、尝试获取锁,参数分别是:waitTime:获取锁的最大等待时间(期间会重试)        // leaseTime:锁自动释放时间  TimeUnit:时间单位        //tryLock(long waitTime, long leaseTime, TimeUnit unit)        boolean isLock=rLock.tryLock(1,100, TimeUnit.SECONDS);        //3、判断锁获取成功及释放        if(isLock){            try {                log.info("执行正常的业务03......");            }catch (Exception e){                log.info("锁获取异常03e:"+e);            }finally {                //锁未关闭,则手动释放锁                if(rLock.isLocked()){                    rLock.unlock();                    log.info("释放锁成功03");                }            }        }    }

输出结果:

具体分析如下:

        在上面的testRedisson02方法中,当外层testRedisson02方法加锁之后,会获取当前的线程标识存入field字段,并将value+1;当内层testRedisson03方法再次加这个锁,会先判断当前线程与field中存的线程是否是一样的,如果是一样的,value+1;此时value为2。如果要解锁,先要判断锁是否是自己的(比对key和field字段),如果是,则value-1。

获取锁的Lua脚本源码:

return evalWriteAsync(getName(), LongCodec.INSTANCE, command,                "if (redis.call('exists', KEYS[1]) == 0) then " +                        "redis.call('hincrby', 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脚本源码

                return evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,"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;",

二、总结

1、不可重入Redis分布式锁:

    原理:利用setnx的互斥性;利用ex避免死锁;释放锁时判

断线程标识。 

    缺陷:不可重入、无法重试、锁超时失效。

2、可重入的Redis分布式锁:

    原理:利用hash结构,记录线程标示和重入次数;利用

watchDog延续锁时间;利用信号量控制锁重试等待。

    缺陷:redis宕机引起锁失效问题。--主从一致性问题

3、RedissonmultiLock:

    原理:多个独立的Redis节点,必须在所有节点都获取重入

锁,才算获取锁成功。

    缺陷:运维成本高、实现复杂。

更多详细资料,请关注个人微信公众号或搜索“程序猿小杨”添加。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3D Web轻量化引擎HOOPS Communicator如何实现对BIM桌面端的支持?

HOOPS Communicator是一款简单而强大的工业级高性能3D Web轻量化渲染开发包,其主要应用于Web领域,主要加载其专有的SCS、SC、SCZ格式文件;HOOPS还拥有另一个桌面端开发包HOOPS Visualize,主要加载HSF、HMF轻量化格式文件。两者虽然…

【QPSK信号生成】生成正交相移键控信号研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

Kubernetes集群部署(第二篇)

安装flannel Master 节点NotReady 的原因就是因为没有使用任何的网络插件,此时Node 和Master的连接还不正常。目前最流行的Kubernetes 网络插件有Flannel、Calico、Canal、Weave 这里选择使用flannel。 flannel提取链接:https://pan.baidu.com/s/1fLJKh…

EXPLAIN使用分析

系列文章目录 文章目录 系列文章目录一、type说明二、MySQL中使用Show Profile1.查看当前profiling配置2.在会话级别修改profiling配置3.查看profile记录4.要深入查看某条查询执行时间的分布 一、type说明 我们只需要注意一个最重要的type 的信息很明显的提现是否用到索引&…

云原生之深入解析Redis的原理分析与环境部署

一、Redis 简介 ① 什么是 Redis ? REmote DIctionary Server(Redis)是一个由 Salvatore Sanfilippo 写的 key-value 存储系统,是跨平台的非关系型数据库。Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可…

在java中如何使用openOffice进行格式转换,word,excel,ppt,pdf互相转换

1.首先需要下载并安装openOffice,下载地址为: Apache OpenOffice download | SourceForge.net 2.安装后,可以测试下是否可用; 3.build.gradle中引入依赖: implementation group: com.artofsolving, name: jodconverter, version:…

mac ssh连接另一台window虚拟机vm

vmware配置端口映射 编辑(E) > 虚拟网络编辑器(N)... > NAT设置(S)... window防火墙,入站规则添加5555端口 控制面板 > 系统和安全 > Windows 防火墙>高级设置>入站规则>新建规则... tips windows查看端口命令:netstat -ano | f…

腾讯云服务器CPU标准型S5/S6/SA3/SR1/SA2处理器大全

腾讯云服务器CVM标准型CPU处理器大全,包括标准型S6、SA3、SR1、S5、S5se、SA2、S4、SN3ne、S3、SA1、S2ne实例CPU处理器型号大全,标准型S6云服务器CPU采用Intel Ice Lake(2.7GHz/3.3GHz),标准型S5采用Intel Xeon Cascade Lake 8255C/Intel Xe…

Python爬虫 爬取图片

在我们日常上网浏览网页的时候,经常会看到一些好看的图片,我们就希望把这些图片保存下载,或者用户用来做桌面壁纸,或者用来做设计的素材。 我们最常规的做法就是通过鼠标右键,选择另存为。但有些图片鼠标右键的时候并没…

Nodejs+vue+elementui汽车租赁管理系统_1ma2x

语言 node.js 框架:Express 前端:Vue.js 数据库:mysql 数据库工具:Navicat 开发软件:VScode 前端nodejsvueelementui, 课题主要分为三大模块:即管理员模块、用户模块和普通管理员模块,主要功能包括&#…

ElasticSearch 7.4学习记录(基础概念和基础操作)

若你之前从未了解过ES,本文将由浅入深的一步步带你理解ES,简单使用ES。作者本人就是此状态,通过学习和梳理,产出本文,已对ES有个全面的了解和想法,不仅将知识点梳理,也涉及到自己的理解&#xf…

Java实战:高效提取PDF文件指定坐标的文本内容

前言 临时接到一个紧急需要处理的事项。业务侧一个同事有几千个PDF文件需要整理:需要从文件中的指定位置获取对应的编号和地址。 要的急,工作量大。所以就问到技术部有没有好的解决方案。 问技术的话就只能写个demo跑下了。 解决办法 1. 研究下PDF文档…