图解ReentrantReadWriteLock读写锁的实现原理

网站建设4年前发布
33 0 0

ReentrantReadWriteLock读写锁是使用AQS的集大成者,用了独占模式和共享模式。本文和大家一起理解下ReentrantReadWriteLock读写锁的实现原理。,2023030701384179cea0e533b170845b4882a5ba34a9633eb4fe571,上图是ReentrantReadWriteLock读写锁的类结构图:,读写锁用的同一个sync同步器,那么他们共享同一个state, 这样不会混淆吗?,不会,ReentrantReadWriteLock读写锁使用了AQS中state值得低16位表示写锁得计数,用高16位表示读锁得计数,这样就可以使用同一个AQS同时管理读锁和写锁。,设计一个加锁场景,t1线程加写锁,t2线程加读锁,我们看下它们整个加锁得流程。,20230307013842c349ba9672dffbbb41b2134188804ebc5a7dc6765,20230307014114c5e97db91b51a73580d6126f8e0c209ed7747f464,2023030701384348b6c6e668407948f5f725915206b039dcdfe7164,20230307013843523ff1181385e3947ea49397d5601b878d05f4161,2023030701411449758b236931a48c08a913466883782993051d181,上面是整个解锁的流程,下面深入源码验证这个流程。,WriteLock类的lock()方法是加写锁的入口方法。,ReadLock​类的lock()​方法是加读锁的入口方法,调用tryAcquireShared()方法尝试获取读锁,返回负数,失败,加入到队列中。,tryAcquireShared()方法是一个模板方法,AQS类中定义语义,子类实现,如果返回1,表示获取锁成功,还有剩余资源,返回0表示获取成功,没有剩余资源,返回-1表示失败。,doAcquireShared()是在获取读锁失败的时候加入AQS队列的逻辑。,由于上面t1线程加的写锁,所有其他的线程都被阻塞了,只有在t1线程解锁以后,其他线程才能被唤醒,我们现在看下t1线程被唤醒了,会发生什么?,t1线程执行解锁w.unlock()成功,修改AQS中的state。,202303070141140624401964a75535d2326092b448cb8cc0396e861,20230307013844570853888afd3b96d9b42067be6d870529a74c509,20230307013845f6c868114d5f11b5689314a6ac857d6ac0c91e390,2023030701384683eef32172222dcefda35964743663a2b92557825,202303070141150661a49526d8c73a53c496c697eef3e7dddd1d260,20230307013849e90ee0134c02a23991d92661d7f032547216b7458,2023030701385098a7836633d546a591962749884fafc3e9528f340,20230307014117f5aef50818f082d93d2337b8551f3676f09cdb808,上面是整个解锁的流程,下面深入源码验证这个流程。,WriteLock类的unlock()方法是入口方法,调用tryRelease()方法释放锁,如果成功,调用unparkSuccessor()方法唤醒线程。,tryRelease()方法是AQS提供的模板方法,返回true表示成功,false失败,由自定义同步器实现。,2.​读锁释放流程,ReadLock​类的unlock()方法是释放共享锁的入口方法。,tryReleaseShared()方法是由AQS提供的模板方法,由自定义同步器实现。,调用doReleaseShared()​方法唤醒等待的线程,这个方法调用的地方有两处,还记得吗,一个这是里的解锁,还有一个是前面加共享锁阻塞的地方,唤醒后获取锁成功,也会调用doReleaseShared()方法。,本文讲解了读写锁ReentrantReadWriteLock的整个加锁、解锁的实现原理,并从源码的角度深入分析,希望对大家有帮助。

© 版权声明

相关文章