JAVA并发(3)-ReentrantReadWriteLock的探索
JAVA并发(3)-ReentrantReadWriteLock的探索
1. 介绍
本文我们继续探究使用AQS的子类ReentrantReadWriteLock(读写锁)。老规矩,先贴一下类图
ReentrantReadWriteLock这个类包含读锁和写锁,这两种锁都存在是否公平的概念,这个后面会细讲。
此类跟ReentrantLock类似,有以下几种性质:
- 可选的公平性政策
- 重入,读锁和写锁同一个线程可以重复获取。写锁可以获取读锁,反之不能
- 锁的降级,重入还可以通过获取写锁,然后获取到读锁,通过释放写锁的方式,从而写锁降级为读锁。 然而,从读锁升级到写锁是不可能的。
- 获取读写锁期间,支持不可中断
2. 源码剖析
先讲几个必要的知识点,然后我们再对写锁的获取与释放,读锁的获取与释放进行讲解,中间穿插着讲公平与非公平的实现。
知识点一:
内部类Sync中,将AQS中的state(private volatile int state;长度是32位)逻辑分成了两份,高16位代表读锁持有的count,低16位代表写锁持有的count
Sync
...
/*
* Read vs write count extraction constants and functions.
* Lock state is logically divided into two unsigned shorts:
* The lower one representing the exclusive (writer) lock hold count,
* and the upper the shared (reader) hold count.
*/
static final int SHARED_SHIFT = 16;
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
/** Returns the number of shared holds represented in count */
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
/** Returns the number of exclusive holds represented in count */
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
...
This lock supports a maximum of 65535 recursive write locks and 65535 read locks. Attempts to exceed these limits result in Error throws from locking methods.(读锁与写锁都最大支持65535个)
知识点二:
HoldCounter的作用,一个计数器记录每个线程持有的读锁count。使用ThreadLocal维护。缓存在cachedHoldCounter
static final class HoldCounter {
int count = 0;
// Use id, not reference, to avoid garbage retention
final long tid = getThreadId(Thread.currentThread());
}
使用ThreadLocal维护