1.啥是读写锁
关于读写锁,顾名思义,就是分别应用于读场景与写场景的两种锁
读锁是共享锁,写锁是排他锁,啥意思呢?
也就是写锁只能独立存在,而读锁可以一起存在
通俗来说,同名读写锁中,当出现写锁时,同名读锁不能加锁,同名写锁也不能加锁
而当存在读书锁时,同名读锁能加锁,但是同名写锁不能加锁。
2.为什莫
其实这都是为了符合数据一致性而设计的,你想一想,
当你写往某张表写数据时,另一个人在往这张表读数据
他是不是要在你写完数据后再读才是读的最新数据呢?这个时候就可以用读写锁来限制
当然,如果你们某些业务上对数据一致性要求不高,那么是不用加读写锁的
当然,你们都是在读,此时都加个读锁,你读你的我读我的,是不影响的,
但是你们在读的时候,另外一个人获取了写锁,准备写,那么能否成功呢?
明显是不行的,因为虽然那边读先进行,这边写后进行,但是并不能保证你写入缓存或者数据库中之前,那边读完了,
如果你先写,另外读的几方是有可能分别读到你写之前与之后数据库的数据的,所以为了一致性,写锁设计成排他锁是很合理的
3.看例子
随便举个例子,这里只弄一种场景的
就是这边写锁未释放前,另一边加读锁是一直阻塞的直到写锁释放才能够成功加读锁开始读
@Autowired
RedissonClient redissonClient;
@Autowired
StringRedisTemplate stringRedisTemplate;
@RequestMapping({"/write"})
@ResponseBody
public void write(){
//获取一把读写锁,只要名称一样就是同一把锁
RReadWriteLock rwLock = redissonClient.getReadWriteLock("rw-lock");
RLock rLock = rwLock.writeLock();
rLock.lock();
try {
Thread.sleep(30000);
String uuid = UUID.randomUUID().toString();
stringRedisTemplate.opsForValue().set("test-key",uuid);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//释放锁
rLock.unlock();
}
}
@RequestMapping({"/read"})
@ResponseBody
public String read(){
//获取一把读写锁,只要名称一样就是同一把锁
RReadWriteLock rwLock = redissonClient.getReadWriteLock("rw-lock");
RLock rLock = rwLock.readLock();
rLock.lock();
String uuid = null;
try {
uuid = stringRedisTemplate.opsForValue().get("test-key");
} catch (Exception e) {
e.printStackTrace();
}finally {
//释放锁
rLock.unlock();
return uuid;
}
}
现象就是上面写的窗口一直转圈,下面读的窗口也是,上面转圈结束写完了写锁释放了,下面就显示了