点评day04 Redisson

一般情况下没有以下特殊需求,基于redis实现的分布式锁已经够用了,但针对以下这些特殊的问题还是存在优化空间的。

首先可重入锁允许同一个线程在已经持有锁的情况下,再次(多次)获取这把锁,而不会造成死锁。你比如说A方法锁A,调用B方法,方法B锁了B,但是要获取A锁,失败,A方法要获取B锁,于是出现死机现象。可重入锁就是你一个线程可以多次调用一个锁(注意释放的时候锁了几次就得释放几次),其实在原本的基础上可以先判断锁是不是自己这个线程的,如果是自己的,就给锁的 value 加 "重入次数"(比如 UUID:2 表示重入 2 次),解锁时,不能直接释放,需要先减次数,只有次数减到 0 才真正删除锁(当然要使用hash结构)。但是我们这里不实现了包括后面说的也不实现了,redesson锁全都可以实现。

然后就是不可重试,我们之前实现的锁就是如果获取失败,直接返回不允许重复下单,没有重试机会。超时释放:虽然我们已经实现了因为线程阻塞导致锁超时释放的问题(就是判断这个锁是不是自己线程的),但是仍然会出现其他问题,也是很严重的。包括主从一致性:就是读写分离,主机写,从机读,我们加锁是写,会写在主机上,主机和从机要同步数据,存在延迟,如果写锁,主机突然岱机,就会出现锁冲突。

这四个问题都可以通过redisson实现,包括以前讲的那些玩意都可以直接通过这个实现。Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务,其中就包含了各种分布式锁的实现。 Redission提供了分布式锁的多种多样的功能(说白了就是一些锁的工具)。

1.配置和使用锁(redisson锁很多,什么红锁什么什么的,具体使用可以自行查看,这里我们用redisson的可重入锁,都可以实现这几个)

复制代码
1.引入依赖:
<dependency>
	<groupId>org.redisson</groupId>
	<artifactId>redisson</artifactId>
	<version>3.13.6</version>
</dependency>
2.配置Redisson客户端:
@Configuration
public class RedissonConfig {
    @Bean
    public RedissonClient redissonClient(){
        // 配置
        Config config = new Config();
        config.useSingleServer().setAddress("redis://192.168.150.101:6379")
            .setPassword("123321");
        // 创建RedissonClient对象
        return Redisson.create(config);
    }
}3.使用的时候
复制代码
//获取锁(可重入),指定锁的名称
    RLock lock = redissonClient.getLock("anyLock");
    //尝试获取锁,参数分别是:获取锁的最大等待时间(期间会重试),锁自动释放时间,时间单位
    boolean isLock = lock.tryLock(1,10,TimeUnit.SECONDS);
    //判断获取锁成功
    if(isLock){
        try{
            System.out.println("执行业务");          
        }finally{
            //释放锁
            lock.unlock();
        }
4.改造代码,就把获取锁对象,改一个方式即可。很简单。        

2.redisson实现可重入的原理,这是基本流程(其实和上面我们分析的一样)

当然你不可能用Java代码写获取锁和释放锁,这么多流程,涉及到原子性,所以要用Lua脚本实现:获取锁的Lua脚本,每个颜色代表一个分支:

释放锁的脚本:

3.redisson实现可重试和超时释放问题就看视频把,这里不说了

4.主从一致性问题:

复制代码
为了解决这个问题,redission提出来了MutiLock锁,使用这把锁就不使用主从了,每个节点的地位都是一样的, 这把锁加锁的逻辑需要写入到每一个节点上,只有所有的服务器都写入成功,此时才是加锁成功,假设现在某个节点挂了,那么他去获得锁的时候,只要有一个节点拿不到,都不能算是加锁成功,就保证了加锁的可靠性。如下图,前一列就是这样的意思,然后有需要的话我们可以给这三个节点去建立主从关系。很明显如果第一个宕机导致它的从节点没锁,也不会获取锁成功,

使用这个连锁:先配置对象,再创建锁,然后连起来

原理:

复制代码
那么MutiLock 加锁原理是什么呢?


当我们去设置了多个锁时,redission会将多个锁添加到一个集合中,然后用while循环去不停去尝试拿锁,但是会有一个总共的加锁时间,这个时间是用需要加锁的个数 * 1500ms ,假设有3个锁,那么时间就是4500ms,假设在这4500ms内,所有的锁都加锁成功, 那么此时才算是加锁成功,如果在4500ms有线程加锁失败,则会再次去进行重试.
相关推荐
天若有情67312 小时前
C++设计模式:tur函数——让对象自我裁决的条件选择器
java·c++·设计模式
无级程序员12 小时前
k8s部署nacos 3.1.1服务,java.net.UnknownHostException问题终极解决方案
java·nacos·kubernetes
C++chaofan12 小时前
JUC 并发编程:不可变对象、享元模式与自定义连接池 学习笔记
java·享元模式·并发编程·连接池·juc·不可变对象
big_rabbit050212 小时前
[算法][力扣242]有效的字母异位词
java·前端·leetcode
xcLeigh12 小时前
复杂 SQL 过滤时机过晚?金仓基于代价的连接条件下推方案来了
java·数据库·sql语句·union·金仓·kingbasees
星轨zb12 小时前
非遗AI对话系统架构升级实战
java·人工智能·redis·后端·系统架构
iPadiPhone12 小时前
Spring Boot 核心注解全维度解析与面试复盘
java·spring boot·后端·spring·面试
青衫客3612 小时前
浅谈 Apache POI:XSSFWorkbook 的原理与实践(Java 操作 Excel 实践指南)
java·apache·excel
沙雕不是雕又菜又爱玩12 小时前
基于springboot的超市收银系统
java·spring boot·intellij-idea
SunnyDays101112 小时前
使用 Java 高效删除 Excel 空白行与空白列
java·删除 excel 空白行·删除 excel 空白列