ReentrantReadWriteLock
1. 前言
- 读写锁,它维护了一对相关的锁 :“读取锁”和“写入锁”,一个用于读取操作,另一个用于写入操作
- 默认不公平模式,支持公平模式,不会强加对锁的读取或写入优先访问顺序
- 写入锁可以降级为读取锁,读取锁不能升级为写入锁
2. 源码解析
2.1 数据结构
- ReentrantReadWriteLock包含一对读锁ReadLock和写锁WriteLock,Sync对象;读锁ReadLock和写锁WriteLock继承自Lock接口,内部的Sync对象和ReentrantReadWriteLock的Sync对象是一样的
- ReentrantReadWriteLock的公平锁和非公平锁由Sync对象实例决定
2.2 内部类
- ReadLock
1 | public static class ReadLock implements Lock, java.io.Serializable { |
- WriteLock
1 | public static class WriteLock implements Lock, java.io.Serializable { |
2.3 共享锁
2.3.1 获取锁
获取共享锁ReadLock思想:首先通过tryAcquireShared()尝试获取;失败则通过doAcquireShared()不断的循环并尝试获取锁,若有需要,则阻塞等待。
- lock()
在ReadLock中获取锁
1 | public void lock() { |
1 | //AQS中实现,获取共享锁 |
- tryAcquireShared
在ReentrantReadWriteLock内部类Sync实现tryAcquireShared()
1 | //尝试获取共享锁 |
其中判断是否需要阻塞readerShouldBlock与锁模式有关:
1 | //FairSync: |
- fullTryAcquireShared
1 | final int fullTryAcquireShared(Thread current) { |
- doAcquireShared
doAcquireShared()的作用是在CLH队列中自旋获取共享锁。doAcquireShared()在每一次尝试获取锁时,是通过tryAcquireShared()来执行的!
1 | private void doAcquireShared(int arg) { |
2.3.2 释放锁
释放共享锁的思想,是先通过tryReleaseShared()尝试释放共享锁。尝试成功的话,则通过doReleaseShared()唤醒“其他等待获取共享锁的线程”,并返回true;否则的话,返回flase。
- unlock()
1 | public void unlock() { |
- releaseShared()
1 | //AQS中实现 |
- tryReleaseShared()
1 | protected final boolean tryReleaseShared(int unused) { |
- doReleaseShared()
1 | //AQS中实现,会释放“共享锁”。从前往后的遍历CLH队列,依次“唤醒”然后“执行”队列中每个节点对应的线程;最终的目的是让这些线程释放它们所持有的锁。 |