1. ReentrantReadWriteLock简介
ReentrantReadWriteLock适合处理读多写少的情况。在没有其他写线程持有该锁的情况下,同步状态是可以被多个读线程持有;如果当前同步状态被写锁持有,那么其他所有线程都将被阻塞。
2. ReentrantReadWriteLock实现
读写锁同样以来自定义同步器来实现同步功能,而读写状态就是其同步器的同步状态。ReentrantLock通过state标识锁的重入次数,那么ReentrantReadWriteLock也需要表示读锁的重入次数和写锁的重入次数,但是只有一个state变量。读写锁通过高16位表示读锁的重入次数,低16位表示写锁的重入次数。
S不等于0时,当写状态(S&0x0000FFFF)等于0时,则读状态(S>>>16)大于0,即读锁已被获取。
2.1 写锁的获取与释放
写锁是一个支持重入的排他锁。
- 写锁的获取
写锁的获取是通过重写AQS中的tryAcquire方法实现的。当读锁已经被其他线程占有的时候,则写锁获取失败,否则支持重入,成功获得锁。
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);
if (c != 0) {
//当读锁已经被读线程获取或者当前线程不是已经获取的写锁,则获取同步状态失败
if (w == 0 || current != getExclusiveOwnerThread())
return false;
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
//重入次数增加
setState(c + acquires);
return true;
}
//c=0,且读锁和写锁都没有被占用,判断写锁是否应该被阻塞
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);
return true;
}
复制代码
-写锁的释放
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
//同步状态减去写状态
int nextc = getState() - releases;
//判断当前线程的写状态是否为0,如果是0则释放写锁
boolean free = exclusiveCount(nextc) == 0;
if (free)
setExclusiveOwnerThread(null);
setState(nextc);
return free;
}
复制代码
2.2 读锁的获取与释放
- 读锁的获取
如果其他线程获取到了写锁,则当前线程获取读锁失败,进入等待状态。如果当前线程获取了写锁或者写锁违背获取,则当前线程增加读状态,成功获取锁。
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
int c = getState();
//如果写锁已经被获取且不是当前线程的话,直接返回
// 如果线程先获取到了写锁,是可以再获取读锁的,这就是锁降级
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
int r = sharedCount(c);
//当前线程获取锁(读线程不应该被阻塞,读锁数量小于最大值,CAS成功)
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
//如果读锁的state为0说明美哟其他线程获取到锁
if (r == 0) {
//把当前线程设为第一个获取到锁的线程
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
//当前线程是第一个获取到锁的线程,重入
firstReaderHoldCount++;
} else {
//读锁的状态不为0,且当前线程不是firstReader
//最近一个成功获取到读锁的线程计数器
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;
}
return 1;
}
return fullTryAcquireShared(current);
}
复制代码
- 读锁的释放
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
if (firstReader == current) {
if (firstReaderHoldCount == 1)
firstReader = null;
else
firstReaderHoldCount--;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
int count = rh.count;
if (count <= 1) {
readHolds.remove();
if (count <= 0)
throw unmatchedUnlockException();
}
--rh.count;
}
for (;;) {
int c = getState();
int nextc = c - SHARED_UNIT;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END