Redisson——ReadWriteLock读写锁
早睡蛋
# 读写锁介绍
基于Redis的Redisson分布式可重入读写锁RReadWriteLock
(opens new window) Java对象实现了java.util.concurrent.locks.ReadWriteLock
接口。其中读锁和写锁都继承了RLock (opens new window)接口。
分布式可重入读写锁允许同时有多个读锁和一个写锁处于加锁状态。
RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock");
// 最常见的使用方法
rwlock.readLock().lock();
// 或
rwlock.writeLock().lock();
1
2
3
4
5
2
3
4
5
大家都知道,如果负责储存这个分布式锁的Redis节点宕机以后,而且这个锁正好处于锁住的状态时,这个锁会出现锁死的状态。为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。默认情况下,看门狗的检查锁的超时时间是30秒钟,也可以通过修改Config.lockWatchdogTimeout (opens new window)来另行指定。
另外Redisson还通过加锁的方法提供了leaseTime
的参数来指定加锁的时间。超过这个时间后锁便自动解开了。
// 10秒钟以后自动解锁
// 无需调用unlock方法手动解锁
rwlock.readLock().lock(10, TimeUnit.SECONDS);
// 或
rwlock.writeLock().lock(10, TimeUnit.SECONDS);
// 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
boolean res = rwlock.readLock().tryLock(100, 10, TimeUnit.SECONDS);
// 或
boolean res = rwlock.writeLock().tryLock(100, 10, TimeUnit.SECONDS);
...
lock.unlock();
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 场景分析
我们知道什么场景下不用加锁,什么场景需要加:
读读:不需要
读写:需要
写写:需要
那为什么不能用一般的锁,读不上锁,写上锁呢?因为假如这样的话,那么在读写场景下,读操作依然可以读取到数据。
# 代码实现Redisson读写锁
创建两个接口,分别为写接口和都接口:
@GetMapping("/test/read/lock/")
public String testReadLock() {
stockService.testReadLock();
return "hello test testReadLock!";
}
@GetMapping("/test/write/lock/")
public String testWriteLock() {
stockService.testWriteLock();
return "hello test testWriteLock!";
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
创建业务方法代码:
/**
* 读锁
*/
public void testReadLock() {
RReadWriteLock rwLock = redissonClient.getReadWriteLock("rwLock");
//上锁(锁10秒)
rwLock.readLock().lock(10, TimeUnit.SECONDS);
// TODO:一系列读操作
//解锁
//rwLock.readLock().unlock();
}
/**
* 写锁
*/
public void testWriteLock() {
RReadWriteLock rwLock = redissonClient.getReadWriteLock("rwLock");
//上锁(锁10秒)
rwLock.writeLock().lock(10, TimeUnit.SECONDS);
// TODO:一系列写操作
//解锁
//rwLock.writeLock().unlock();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 测试
- 我们开启两个浏览器窗口,首先请求读接口,程序正常运行,并加了锁。
- 然后再次请求读接口,虽然加了锁,但是仍然请求成功
- 这时我们请求写接口,发现请求响应比较久,在等锁过期之后,写请求才响应成功。
- 我们换个顺序,先请求写接口,然后再请求读接口,发现请求读接口的响应结果也是要等到锁过期才能执行。
Redisson的读写锁中是判断读锁和写锁的数量的,只能存在一个写锁。