在上一系列文章中,我们分析了JUC的核心实施,例如AQS等。
ReentrantreamWritelock的基础是AQS,因此最好先掌握AQS的原理。您首先可以理解本文的前沿知识点:
重新进入的效果是完全谴责他的替代方案,也就是说,只有一个线程是由reentrantlock.lock()方法背后的任务执行的。
尽管这保证了实例变量的线程安全性,但并行效率是比较。因此,读写锁的出现将加速操作效率;
与一般场合的重新输入锁相比,ReadWritelock适用的情况,合理的使用可以进一步提高并发效率。
读写锁中有两个锁,一个是与读取操作相关的锁,称为;另一个是与操作相关的锁,也称为。多元读取不谴责,相互排除读取锁和写作锁,以及锁和写锁。
在这两个锁中,第一个锁是锁。获得锁后,可以读取数据并可以修改数据,第二个锁定是读取锁。获得锁后,您只能查看数据。无法修改数据。可以同时使用多个线程持有锁定锁,因此多个线程可以同时查看数据。
合理地使用读取锁,代替阅读,合理地使用写作锁,并灵活地控制它,这可以提高程序的执行效率
ReentrantreamWritelock使用16位状态来指示锁定的计数,并使用另一个16位状态来表示读取锁的计数。
读取锁上的操作将使用共享方法和释放方法,锁的操作将使用垄断方法和释放方法。
您可以从上面的示例中看到
在ReentrantreamWritelock中,国家的含义:
提供持有结构,保存每个阅读线程和重复时间的数量
通过确保线程之间的变量隔离,也就是说,每个线程都有自己的holdCounter对象
通过CachedholdCounter来缓存最近获得成功读取的成功线程的最近观点,这可以避免通过一次使用此字段来判断的线路搜索。
Firstreader字段记录了获得成功阅读锁的第一个线程,而FirstreaderHoldCount是相应的HoldCount信息。
因为第一个线程是特殊的,所以它是共享模式中的第一个将状态从“ 0”更改为“ 1”,也就是说,只要线程固定锁,firstreader就不是空的。
澄清上述关键变量,并且了解ReentrantReadWritelock更加容易
1.1,TryAcquire尝试获取锁资源
TryAcquire用于在垄断模式下获得资源。这里
如果实现非锁定锁,您可以尝试抓住锁定资源
1.2。TryRelease尝试是否将资源锁定以在垄断模式下发布锁定资源。
资源的发布相对简单,总资源量(总权重) - 需要发布的资源量以获取剩余的资源量。如果其余资源量等于0
2.1,TryAcquireshared试图以共享模式获得资源,此处也旨在阅读锁
此方法是在共享模式下获取资源。在ReentrantreadWritelock中,即获得锁定资源。有几个步骤:
2.1.1 FulltryAcquireShaared
整个方法是相对常规的。通常,这是为了确保通过Spin+CAS在多线程竞争下获得资源;对于每个线程的读取锁的数量
2.2 TryReleaseshared共享模式发布,这是读取锁定资源的发行版
在这种情况下,旋转用于确保可以释放资源,因为读取锁可以由多个线程保存,因此CAS操作也可以可用。
2.3 Trywritelock尝试获得写锁
2.4试图获取锁定锁
确保通过旋转+CAS获得锁定资源
2.5 getRearholdCount以获取读取锁的重新读数的数量
只要您等待队列等待节点,就无法抓住资源。您只能按排队排队以根据FIFO的方法获得资源,也就是说,不允许排队
应在锁定模式的非审判中注意到这一点。为了避免需要写锁的线程的无限等待。如果队列的第一个节点是获取锁的线程,那么这里的读取锁将不会走。
为什么锁线显示“饥饿”?
看一个示例:
它是指同一线程,首先获得写作锁,然后您可以再次获得读取锁。
为什么需要锁定降级?
为什么不支持锁的升级?
内部维护等待线程队列,该线程记录线程请求是独家访问还是共享访问权限。
在ReentrantreadWritelock中,当可用锁时,如果执行了队列的头部(想要获取写锁),则该线程将获得此锁。获取读取锁),然后在第一个线程之前所有线程队列中的编写线程将获得此锁;
对于第二种情况,为了防止写锁线“”
阅读和写作锁的获取规则
总结为:
促进策略:
原始:https://juejin.cn/post/7100933816142954532相关文档: