读写锁的一些错误记忆修正

Posted silentdoer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了读写锁的一些错误记忆修正相关的知识,希望对你有一定的参考价值。

1.先以一段代码为例

ReadWriteLock rwLock = new ReentrantReadWriteLock();

// rwLock.readLock()是获取rwLock里的一个属性而非new
// 这句代码的意思是给rwLock加读锁,而不应该理解为给rwLock.readLock()的返回值加锁
// 这点Go比java好,go里读写锁就是提供四个方法,而java里拆成两个属性来提供让人误解
rwLock.readLock().lock();

2.读写锁对象里的读锁属性rwLock.readLock()和写锁属性rwLock.writeLock()里加锁或者释放锁都是针对rwLock的而非针对其读锁属性或写锁属性;

3.之前有个错误的记忆,就是读写锁rwLock如果加了读锁后,加写锁会被阻塞,此时再给rwLock加读锁是不会成功的,这个记忆是错误的;rwLock只要当前状态是已经被加了读锁状态,不管此时是否存在某个线程要给rwLock加写锁(会被阻塞)

,再给它加读锁都是成功的;

4.每次加锁都会保存一个锁数据,这个锁数据里包含了线程信息;java里在A线程里加了某个锁(包括普通锁和读写锁),那么一定要在该线程释放对应的锁(如普通锁,或者读写锁的读锁或写锁);(Go里没有这个要求,在A线程加锁,可以在B线程释放锁,而且Go的锁不是可重入的)

5.加了多少次锁就要释放多少次锁,比如普通lock在一个代码块里lock了两次,那么就必须unlock两次,否则其他地方仍然是无法获得锁的;这个同样适用于读锁,比如rwLock加了3次读锁,这个时候写锁被阻塞,必须释放三次读锁写锁才会获得加锁的权限;

6.rwLock加了写锁后,然后存在一个加写锁的被阻塞和加读锁的被阻塞的两个线程,此时释放rwLock的写锁,然后这两个阻塞的线程会公平的去“争抢”rwLock的写锁或读锁(而不是因为之前的是写锁,所以下一个一定是优先写锁或读锁)

,经过测试,到底是谁“争抢”成功,主要看这两个线程哪个先运行到rwLock加读/写锁的那句代码,先被阻塞的会先被唤醒去获得锁(当然不同的JVM可能不一样,所以这个不能当定论,只能说我的JVM测试结果是这样);

以上是关于读写锁的一些错误记忆修正的主要内容,如果未能解决你的问题,请参考以下文章

手写数字识别——基于全连接层和MNIST数据集

只有一个底层锁的读写锁?

AQS系列- ReentrantReadWriteLock读写锁的加锁

ReentrantReadWriteLock读写锁的使用

一张图帮你记忆,Spring Boot 应用在启动阶段执行代码的几种方式

用信号量和读写锁解决读者写者问题