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

大家都知道,如果负责储存这个分布式锁的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

# 场景分析

我们知道什么场景下不用加锁,什么场景需要加:

读读:不需要

读写:需要

写写:需要

那为什么不能用一般的锁,读不上锁,写上锁呢?因为假如这样的话,那么在读写场景下,读操作依然可以读取到数据。

# 代码实现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

创建业务方法代码:

    /**
     * 读锁
     */
    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

# 测试

  1. 我们开启两个浏览器窗口,首先请求读接口,程序正常运行,并加了锁。
  2. 然后再次请求读接口,虽然加了锁,但是仍然请求成功
  3. 这时我们请求写接口,发现请求响应比较久,在等锁过期之后,写请求才响应成功。
  4. 我们换个顺序,先请求写接口,然后再请求读接口,发现请求读接口的响应结果也是要等到锁过期才能执行。

Redisson的读写锁中是判断读锁和写锁的数量的,只能存在一个写锁。