点评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有线程加锁失败,则会再次去进行重试.
相关推荐
利刃大大2 小时前
【SpringCloud】Gateway Filter Factories && 过滤器执行顺序 && 自定义过滤器
java·后端·网关·spring cloud·gateway
Andy Dennis2 小时前
Java&Go 内存管理
java·jvm·go
xuzhiqiang07249 小时前
Java进阶之路,Java程序员职业发展规划
java·开发语言
时艰.9 小时前
订单系统历史数据归档方案
java
一只叫煤球的猫11 小时前
ThreadForge v1.1.0 发布:让 Java 并发更接近 Go 的开发体验
java·后端·性能优化
014.11 小时前
2025最新jenkins保姆级教程!!!
java·运维·spring boot·spring·jenkins
浣熊88811 小时前
天机学堂虚拟机静态ip无法使用(重启后ip:192.168.150.101无法使用连接Mobaxterm数据库等等,或者无法使用修改之后的Hosts域名去访问nacos,jenkins)
java·微服务·虚拟机·天机学堂·重启之后静态ip用不了
心 -12 小时前
java八股文IOC
java
I_LPL13 小时前
day34 代码随想录算法训练营 动态规划专题2
java·算法·动态规划·hot100·求职面试