共计 2498 个字符,预计需要花费 7 分钟才能阅读完成。
本文章转自:乐字节
文章次要解说:Redisson
获取更多 Java 相干材料能够关注公众号《乐字节》发送:999
咱们先来看下 Redis 官网对分布式锁的说法:
而 Java 版的 分布式锁的框架就是 Redisson。
一、Redisson 是什么?
如果你之前是在用 Redis 的话,那应用 Redisson 的话将会事倍功半,Redisson 提供了应用 Redis 的最简略和最便捷的办法。
Redisson 的主旨是促成使用者对 Redis 的关注拆散(Separation of Concern),从而让使用者可能将精力更集中地放在解决业务逻辑上。
Redisson 是一个在 Redis 的根底上实现的 Java 驻内存数据网格(In-Memory Data Grid)。
二、整合 Redisson
Spring Boot 整合 Redisson 有两种计划:
本篇介绍如何用程序化的形式整合 Redisson。
2.1 引入 Maven 依赖
在 passjava-question 微服务的 pom.xml 引入 redisson 的 maven 依赖。
2.2 自定义配置类
上面的代码是单节点 Redis 的配置。
2.3 测试配置类
新建一个单元测试办法。
咱们运行这个测试方法,打印出 redissonClient
三、分布式可重入锁
3.1 可重入锁测试
基于 Redis 的 Redisson 分布式可重入锁 RLockJava 对象实现了 java.util.concurrent.locks.Lock 接口。同时还提供了异步(Async)、反射式(Reactive)和 RxJava2 规范的接口。
咱们用 passjava 这个开源我的项目测试下可重入锁的两个点:
3.1.1 验证一:可重入锁是阻塞的吗?
为了验证以上两点,我写了个 demo 程序:代码的流程就是设置 WuKong-lock 锁,而后加锁,打印线程 ID,期待 10 秒后开释锁,最初返回响应:“test lock ok”。
先验证第一个点,用两个 http 申请来测试抢占锁。
申请的 URL:
第一个线程对应的线程 ID 为 86,10 秒后,开释锁。在这期间,第二个线程须要期待锁开释。
第一个线程开释锁之后,第二个线程获取到了锁,10 秒后,开释锁。
画了一个流程图,帮忙大家了解。如下图所示:
由此能够得出结论,Redisson 的可重入锁(lock)是阻塞其余线程的,须要期待其余线程开释的。
3.1.2 验证二:服务停了,锁会开释吗?
如果线程 A 在期待的过程中,服务忽然停了,那么锁会开释吗?如果不开释的话,就会成为死锁,阻塞了其余线程获取锁。
咱们先来看下线程 A 的获取锁后的,Redis 客户端查问到的后果,如下图所示:
WuKong-lock 有值,而且大家能够看到 TTL 在一直变小,阐明 WuKong-lock 是自带过期工夫的。
通过观察,通过 30 秒后,WuKong-lock 过期隐没了。阐明 Redisson 在停机后,占用的锁会主动开释。
那这又是什么原理呢?这里就要提一个概念了,看门狗。
3.2 看门狗原理
如果负责贮存这个分布式锁的 Redisson 节点宕机当前,而且这个锁正好处于锁住的状态时,这个锁会呈现锁死的状态。为了防止这种状况的产生,Redisson 外部提供了一个监控锁的看门狗,它的作用是在 Redisson 实例被敞开前,一直的缩短锁的有效期。
默认状况下,看门狗的查看锁的超时工夫是 30 秒钟,也能够通过批改 Config.lockWatchdogTimeout 来另行指定。
如果咱们未制订 lock 的超时工夫,就应用 30 秒作为看门狗的默认工夫。只有占锁胜利,就会启动一个定时工作:每隔 10 秒从新给锁设置过期的工夫,过期工夫为 30 秒。
如下图所示:
3.3 设置锁过期工夫
咱们也能够通过给锁设置过期工夫,让其主动解锁。
如下所示,设置锁 8 秒后主动过期。
如果业务执行工夫超过 8 秒,手动开释锁将会报错,如下图所示:
所以咱们如果设置了锁的主动过期工夫,则执行业务的工夫肯定要小于锁的主动过期工夫,否则就会报错。
四、王者计划
因为 Redisson 十分弱小,实现分布式锁的计划十分简洁,所以称作王者计划。
原理图如下:
代码如下所示:
和之前 Redis 的计划相比,简洁很多。
上面解说下 Redisson 的其余几种分布式锁,置信大家在当前的我的项目中也会用到。
五、分布式读写锁
基于 Redis 的 Redisson 分布式可重入读写锁 RReadWriteLock Java 对象实现了 java.util.concurrent.locks.ReadWriteLock 接口。其中读锁和写锁都继承了 RLock 接口。
写锁是一个排他锁(互斥锁),读锁是一个共享锁。
示例代码如下:
另外 Redisson 还通过加锁的办法提供了 leaseTime 的参数来指定加锁的工夫。超过这个工夫后锁便主动解开了。
六、分布式信号量
基于 Redis 的 Redisson 的分布式信号量(Semaphore)Java 对象 RSemaphore 采纳了与 java.util.concurrent.Semaphore 类似的接口和用法。同时还提供了异步(Async)、反射式(Reactive)和 RxJava2 规范的接口。
对于信号量的应用大家能够设想一下这个场景,有三个停车位,当三个停车位满了后,其余车就不停了。能够把车位比作信号,当初有三个信号,停一次车,用掉一个信号,车来到就是开释一个信号。
咱们用 Redisson 来演示上述停车位的场景。
先定义一个占用停车位的办法:
再定义一个来到车位的办法:
为了简便,我用 Redis 客户端增加了一个 key:“park”,值等于 3,代表信号量为 park,总共有三个值。
而后用 postman 发送 park 申请占用一个停车位。
而后在 redis 客户端查看 park 的值,发现曾经改为 2 了。持续调用两次,发现 park 的等于 0,当调用第四次的时候,会发现申请始终处于期待中,阐明车位不够了。如果想要不阻塞,能够用 tryAcquire 或 tryAcquireAsync。
咱们再调用来到车位的办法,park 的值变为了 1,代表车位残余 1 个。
留神:屡次执行开释信号量操作,残余信号量会始终减少,而不是到 3 后就封顶了。
其余分布式锁:
感激大家的认同与反对,小编会继续转发《乐字节》优质文章