分布式锁Redisson之读写锁
简介
保证一定能读到最新数据,修改期间写锁是互斥锁(排他锁)。读锁是一个共享锁
- 写锁没释放读就必须等待
- 读 + 读:相当于无锁,并发读只会在Redis中记录好,所有当前的读锁。它们都会同时加锁成功
- 写 + 读:等待写锁释放
- 写 + 写:阻塞方式
- 读 + 写:有读锁,写也需要等待
- 只要有写* 锁的时候,都得等待
简单用法
分布式可重入读写锁允许同时有多个读锁和一个写锁处于加锁状态。
RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock");
// 最常见的使用方法
rwlock.readLock().lock();
// 或
rwlock.writeLock().lock();
另外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();
测试
/**
* 写锁
*
* @return
*/
@GetMapping("/write")
@ResponseBody
public String writeLock() {
String s = "";
RReadWriteLock readWriteLock = redisson.getReadWriteLock("rw-lock");
RLock rLock = readWriteLock.writeLock();
try {
//1、改数据加写锁,读数据加读锁
rLock.lock();
s = UUID.randomUUID().toString();
redisTemplate.opsForValue().set("writeValue", s);
Thread.sleep(30000);
} catch (Exception e) {
} finally {
rLock.unlock();
}
return s;
}
/**
* 读锁
* @return
*/
@GetMapping("/read")
@ResponseBody
public String readLock() {
RReadWriteLock readWriteLock = redisson.getReadWriteLock("rw-lock");
RLock rLock = readWriteLock.readLock();
String s = "";
try {
//加读锁
rLock.lock();
s = redisTemplate.opsForValue().get("writeValue");
} catch (Exception e) {
} finally {
rLock.unlock();
}
return s;
}
测试:
在redis中新建一个键值对用来测试读
读取成功
当我们去写的时候,发现读的接口一直在转圈加载,这说明我们写锁生效了,读锁被阻塞等待了,当写锁执行完释放锁,读锁才能执行。
并且当写锁执行业务进行更新时,我们的读锁读到的是最新的数据。