Java—多线程8 ReentranReadWriteLock可重入读写锁
读写者模型
读写锁允许同一时刻被多个读线程访问,但在写线程访问时,所有的读线程以及其他写线程均会被阻塞。
写锁是一个独占锁:
读锁!= 无锁:
如果 读锁==无锁,当有写线程时,读线程不会停止。
如果 读锁!=写锁 当有写线程访问时,读线程会被停止
写锁—独占锁
1.写锁的获取:
protected final boolean tryAcquire(int acquires) {
//1.当前的读写锁没有被任何读线程获取,并且写锁要么是0要么被自己拿着(可重入)
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;
}
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
//此时读写状态为0,写锁可以正常获取到同步状态
//当前线程置为写锁线程
setExclusiveOwnerThread(current);
return true;
}
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;//左移16位
static final int SHARED_SHIFT = 16;
如何区分读状态和写状态
同步状态的高16位表示 读锁的次数;同步状态的低16位表示 写锁的次数
2.写锁的释放
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);
//不为0则更新同步状态
setState(nextc);
return free;
}
读锁—共享锁(一般与独占锁搭配使用实现读写者模型)
获取:只要当前没有写线程获取到写锁,并且读锁的获取次数不超过最大值,读锁就可以获取成功。
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);
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
if (r == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
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);
}
释放:自旋,将同步状态减去读状态即可,如果减到0,就可以释放锁
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
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;
}
}
应用场景:所有缓存的实现必有读写锁,缓存一定是个共享资源,
写锁的降级
写锁可以降级成写锁,写锁不能降级成读锁。