Redisson入门
- 导入依赖
XML
|
|
- 配置Redisson客户端,在config包下新建
RedissonConfig
类
JAVA
|
|
- 使用Redisson的分布式锁
JAVA
|
|
- 替换我们之前自己写的分布式锁
JAVA
|
|
- 使用Jmeter进行压力测试,依旧是只能抢到一张优惠券,满足我们的需求
Redisson可重入锁原理
-
在Lock锁中,他是借助于等曾的一个voaltile的一个state变量来记录重入的状态的
- 如果当前
没有
人持有这把锁,那么state = 0
- 如果
有
人持有这把锁,那么state = 1
- 如果持有者把锁的人再次持有这把锁,那么state会
+1
- 如果持有者把锁的人再次持有这把锁,那么state会
- 如果对于
synchronize
而言,他在c语言代码中会有一个count - 原理与
state
类似,也是重入一次就+1
,释放一次就-1
,直至减到0,表示这把锁没有被人持有
- 如果当前
-
在redisson中,我们也支持可重入锁
- 在分布式锁中,它采用hash结构来存储锁,其中外层key表示这把锁是否存在,内层key则记录当前这把锁被哪个线程持有
-
method1在方法内部调用method2,method1和method2出于同一个线程,那么method1已经拿到一把锁了,想进入method2中拿另外一把锁,必然是拿不到的,于是就出现了死锁
@Resource
private RedissonClient redissonClient;
private RLock lock;
@BeforeEach
void setUp() {
lock = redissonClient.getLock("lock");
}
@Test
void method1() {
boolean success = lock.tryLock();
if (!success) {
log.error("获取锁失败,1");
return;
}
try {
log.info("获取锁成功");
method2();
} finally {
log.info("释放锁,1");
lock.unlock();
}
}
void method2() {
RLock lock = redissonClient.getLock("lock");
boolean success = lock.tryLock();
if (!success) {
log.error("获取锁失败,2");
return;
}
try {
log.info("获取锁成功,2");
} finally {
log.info("释放锁,2");
lock.unlock();
}
}
- 所以我们需要额外判断,method1和method2是否处于同一线程,如果是同一个线程,则可以拿到锁,但是state会
+1
,之后执行method2中的方法,释放锁,释放锁的时候也只是将state进行-1
,只有减至0,才会真正释放锁 - 由于我们需要额外存储一个state,所以用字符串型
SET NX EX
是不行的,需要用到Hash
结构,但是Hash
结构又没有NX
这种方法,所以我们需要将原有的逻辑拆开,进行手动判断
Redisson锁的MutiLock原理
-
为了提高Redis的可用性,我们会搭建集群或者主从,现在以主从为例
-
此时我们去写命令,写在主机上,主机会将数据同步给从机,但是假设主机还没来得及把数据写入到从机去的时候,主机宕机了
-
哨兵会发现主机宕机了,于是选举一个slave(从机)变成master(主机),而此时新的master(主机)上并没有锁的信息,那么其他线程就可以获取锁,又会引发安全问题
-
为了解决这个问题。Redisson提出来了MutiLock锁,使用这把锁的话,那我们就不用主从了,每个节点的地位都是一样的,都可以当做是主机,那我们就需要将加锁的逻辑写入到每一个主从节点上,只有所有的服务器都写入成功,此时才是加锁成功,假设现在某个节点挂了,那么他去获取锁的时候,只要有一个节点拿不到,都不能算是加锁成功,就保证了加锁的可靠性