《伸手系列》之分布式锁Redssion入门和源码解析

Redisson简介

Javaer都知道Jedis,Jedis是Redis的Java实现的客户端,其API提供了比较全面的Redis命令的支持。Redission也是Redis的客户端,相比于Jedis功能简单。Jedis简单使用阻塞的I/O和redis交互,Redission通过Netty支持非阻塞I/O。Jedis最新版本2.9.0是2016年的快3年了没有更新,而Redission最新版本是2018.10月更新。
Redission封装了锁的实现,其继承了java.util.concurrent.locks.Lock的接口,让我们像操作我们的本地Lock一样去操作Redission的Lock。
下面直接上干货

使用样例

@GetMapping("/testLock")
	public String lock(){
	    
		RLock lock = redissonClient.getLock("anyLock");

		lock.lock();

		try {
				System.out.println(lock);
				Thread.sleep(TimeUnit.SECONDS.toMillis(30));
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
		    lock.unlock();
		}
		
		return "ok" ;
	}

源码分析

  • 获取锁
    在这里插入图片描述

调用getLock()方法后实际返回一个RedissonLock对象

  • 加锁
    在这里插入图片描述

在RedissonLock对象的lock()方法主要调用tryAcquire()方法,由于leaseTime == -1,于是走tryLockInnerAsync()方法

  • 加锁细节
    在这里插入图片描述

结合上面的参数声明,我们可以知道,这里KEYS[1]就是getName(),ARGV[2]是getLockName(threadId),假设前面获取锁时传的name是“anyLock”,假设调用的线程ID是Thread-1,假设成员变量UUID类型的id是85b196ce-e6f2-42ff-b3d7-6615b6748b5d:65那么KEYS[1]=anyLock,ARGV[2]=85b196ce-e6f2-42ff-b3d7-6615b6748b5d:Thread-1 ,因此,这段脚本的意思是1、判断有没有一个叫“anyLock”的key2、如果没有,则在其下设置一个字段为“85b196ce-e6f2-42ff-b3d7-6615b6748b5d:Thread-1”,值为“1”的键值对 ,并设置它的过期时间3、如果存在,则进一步判断“85b196ce-e6f2-42ff-b3d7-6615b6748b5d:Thread-1”是否存在,若存在,则其值加1,并重新设置过期时间4、返回“anyLock”的生存时间(毫秒)

  • 加锁redis结构
    在这里插入图片描述

这里用的数据结构是hash,hash的结构是: key 字段1 值1 字段2 值2 。。。用在锁这个场景下,key就表示锁的名称,也可以理解为临界资源,字段就表示当前获得锁的线程所有竞争这把锁的线程都要判断在这个key下有没有自己线程的字段,如果没有则不能获得锁,如果有,则相当于重入,字段值加1(次数)

  • 解锁
    在这里插入图片描述

我们还是假设name=anyLock,假设线程ID是Thread-1,同理,我们可以知道KEYS[1]是getName(),即KEYS[1]=anyLock,KEYS[2]是getChannelName(),即KEYS[2]=redisson_lock__channel:{anyLock},ARGV[1]是LockPubSub.unlockMessage,即ARGV[1]=0,ARGV[2]是生存时间,ARGV[3]是getLockName(threadId),即ARGV[3]=85b196ce-e6f2-42ff-b3d7-6615b6748b5d:Thread-1,因此,上面脚本的意思是:1、判断是否存在一个叫“anyLock”的key2、如果不存在,向Channel中广播一条消息,广播的内容是0,并返回1。3、如果存在,进一步判断字段85b196ce-e6f2-42ff-b3d7-6615b6748b5d:Thread-1是否存在。4、若字段不存在,返回空,若字段存在,则字段值减1,5、若减完以后,字段值仍大于0,则返回0。6、减完后,若字段值小于或等于0,则广播一条消息,广播内容是0,并返回1;可以猜测,广播0表示资源可用,即通知那些等待获取锁的线程现在可以获得锁了

  • 等待
 private void lock(long leaseTime, TimeUnit unit, boolean interruptibly) throws InterruptedException {
        long threadId = Thread.currentThread().getId();
        Long ttl = tryAcquire(leaseTime, unit, threadId);
        // lock acquired
        if (ttl == null) {
            return;
        }

        RFuture<RedissonLockEntry> future = subscribe(threadId);
        if (interruptibly) {
            commandExecutor.syncSubscriptionInterrupted(future);
        } else {
            commandExecutor.syncSubscription(future);
        }

        try {
            while (true) {
                ttl = tryAcquire(leaseTime, unit, threadId);
                // lock acquired
                if (ttl == null) {
                    break;
                }

                // waiting for message
                if (ttl >= 0) {
                    try {
                        future.getNow().getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
                    } catch (InterruptedException e) {
                        if (interruptibly) {
                            throw e;
                        }
                        future.getNow().getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
                    }
                } else {
                    if (interruptibly) {
                        future.getNow().getLatch().acquire();
                    } else {
                        future.getNow().getLatch().acquireUninterruptibly();
                    }
                }
            }
        } finally {
            unsubscribe(future, threadId);
        }
//        get(lockAsync(leaseTime, unit));
    }

这里会订阅Channel,当资源可用时可以及时知道,并抢占,防止无效的轮询而浪费资源当资源可用用的时候,循环去尝试获取锁,由于多个线程同时去竞争资源,所以这里用了信号量,对于同一个资源只允许一个线程获得锁,其它的线程阻塞

  • 总结
    在这里插入图片描述
    在这里插入图片描述

关注Github:1/2极客

关注博客:御前提笔小书童

关注网站:HuMingfeng

关注公众号:开发者的花花世界

热门文章

暂无图片
编程学习 ·

3.1.2 Jsoup请求URL

org.jsoup.Jsoup类可以用来处理连接操作。在org.jsoup.Jsoup类中提供了connect(String url)方法来创建一个新连接,该方法的实现依赖于Java网络通信包java.net。在创建连接之后,可通过具体请求方法(GET或POST等)获取URL对应的HTML文件。 如需要采集某页面中的文本内容。首先,…
暂无图片
编程学习 ·

springboot+idea+bootstrap的带有图片的表格编辑操作

前面已经写了 批量导入,图片显示,现在写的是批量修改,后面会写用echarts+springboot 做折线图,有时间贴上 1、jsp代码如下,编辑按钮formatter: function (value, row, index) {var edit = <input class="btn btn-primary" type="button" value=&qu…
暂无图片
编程学习 ·

Java设计模式-单例模式(全例记录)

1. 基础介绍核心作用:保证一个类只有一个实例,并提供一个访问该实例的全局访问点; 优点:由于单例模式只生成一个实例,所以减少了系统的开销,当一个系统启动需要较多的资源时,可以直接在系统启动时产生一个单例对象,然后使其永久驻留内存;单例模式可以在系统设置全局访…
暂无图片
编程学习 ·

什么是体感互动以及其优势在哪

体感互动通常指的是隔空互动,通过体感设备,来检测人体,通过景物深度处理技术把人物从摄像头捕捉到的画面中分离出来; 随着手指的挥动、在不接触任何物体的情况下做出手势,根据自己的要求发出一些信号,画面就会做出相应的变化,例如对图片、视频进行放大缩小、拖拽、旋转、播…
暂无图片
编程学习 ·

常用排序:冒泡排序与快速排序详解,看完这篇就够了!风马博客

常用排序:冒泡排序与快速排序详解。在排序算法中,冒泡排序和快速排序可以算是排序算法入门必会的两种排序了,今天和大家来分析一下如何快速理解并掌握这两种排序。首先冒泡排序是初学者最常用的排序,所以我们先来详解下冒泡排序。1.冒泡排序冒泡排序,看字面意义就是有大泡泡…
暂无图片
编程学习 ·

画图-身份证

画图函数:base_dir = f{main.BASE_DIR}/quality_management_logic/dataCenter/self.draw.text((55, self.height * 0.31), self.personName, (0, 0, 0),font=ImageFont.truetype(os.path.join(base_dir, msyh.ttc),24)) #personname应用: # -*- coding: utf-8 -*- # import …
暂无图片
编程学习 ·

使用MicroPython计算任意位数圆周率

计算任意精度的圆周率是个有趣的主题,得益于python的强大计算能力,我们在MicroPython中也可以轻松的计算pi的数值。先输入下面的代码:""" 文件:pi.py 说明:用MicroPython计算任意精度圆周率计算 作者:未知 版本: 时间: 修改:邵子扬2016.5v1.1 http://b…
暂无图片
编程学习 ·

nginxj简单安装文档

安装依赖包yum -y install pcre-develyum -y install openssl-develyum -y install gccyum -y install lrzszyum -y install openssh-clients安装nginx上传su - root1、cd /usr/local2、rz –y解压tar -xzvf nginx-1.7.7.tar.gz重命名mv nginx-1.7.7 nginx安装nginx进入解压后的…
暂无图片
编程学习 ·

加速推进新基建,中国联通软件研究院助力广东智造云升级为全国工业平台

加速推进新基建,中国联通软件研究院助力广东智造云升级为全国工业平台发稿时间:2020-07-01 11:260【字体: 大 中 小】6月23日,中国联通智造云全国级工业市场顺利完成上线,6月28日,智造云产品成功在湖北省签约下单,打破了省内地域的限制,实现了省分政企创新业务迈向全国…
暂无图片
编程学习 ·

近三位数增长,苏宁银行金融科技之花结出普惠金融之果

文|曾响铃来源|科技向令说(xiangling0815)美联储无限QE,2020年中国不设GDP目标,2万亿直达基层扶危纾困……国内疫情已经基本控制,经济基本面迎来全面复苏阶段,作为市场中最活跃的存在之一,小微企业在复苏过程中,面临的融资难等问题也被热议。在中国有一群喊着帮助小微企…
暂无图片
编程学习 ·

http相关

http相关下载文件 下载文件 //处理中文文件名乱码if (request.getHeader("User-Agent").toUpperCase().contains("MSIE") ||request.getHeader("User-Agent").toUpperCase().contains("TRIDENT")|| request.getHeader("User-Agen…
暂无图片
编程学习 ·

Redis持久化

Redis的持久化1. RDB持久化2. AOF持久化 ​ Redis是内存数据库,里面存储的是自己的数据库状态,因此为了保证在意外情况下数据库状态的一致性,Redis提供了持久化功能。 1. RDB持久化 ​ 该功能就是将某个时间点上的数据库状态保存到一个RDB文件中,RDB文件是一个经过压缩的二…
暂无图片
编程学习 ·

【leetcode C语言实现】剑指 Offer 07.重建二叉树

题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 例如,给出 前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = [9,3,15,20,7] 返回如下的二叉树:限制: 0 <= 节点个数 <= 5000 来源:…
暂无图片
编程学习 ·

TCP/IP协议基础知识笔记

1.TCP/IP协议包括FTP、SMTP、TCP、UDP、IP五中协议 。 2.TCP/IP四层体系结构:应用层、传输层、网络层、数据链路层。 3.TCP传输层协议,IP 网络层协议。 4.链路层:数据包必须是从一块网卡传送到另一块网卡。而网卡地址就是数据包的发送地址和接收地址 5.IP地址与域名均是一一…
暂无图片
编程学习 ·

LeetCode-Algorithms-[Easy]509. 斐波那契数

斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: F(0) = 0, F(1) = 1 F(N) = F(N - 1) + F(N - 2), 其中 N > 1. 给定 N,计算 F(N)。 示例 1:输入:2 输出:1 解释:F(2) = F(1) + F…
暂无图片
编程学习 ·

https://www.cnblogs.com/sunsky303/p/7731911.html https://blog.csdn.net/lilele12211104/article/details/80393463
暂无图片
编程学习 ·

centos7源码安装mariadb10.4.16(脚本)

#!/bin/bash #auto SourceCode Install mariadb #by author toyix #2020年7月2日 13:14:14 yum install -y wget lrzsz vim echo "安装阿里base及epel源" wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo wget -O /etc/yu…