读写锁允许同一时刻被多个读线程访问,但是在写线程访问时,所有的读线程和其他的写线程都会被阻塞。
ReentrantReadWriteLock特性:
阅读之前的一些思考:
获取读锁
场景:多线程安全操作下,读的情况多于写的情况,满足多线程操作的安全性,也要确保性能不能太差。
// AQS中的获取共享锁的方法
public final void acquireShared(int arg) {
// 小于0表示获取失败进入进入队列
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
// ReentrantReadWriteLock->Sync中获取共享锁的实现
protected final int tryAcquireShared(int unused) {
/*
* Walkthrough:
* 1. If write lock held by another thread, fail.
* 2. Otherwise, this thread is eligible for
* lock wrt state, so ask if it should block
* because of queue policy. If not, try
* to grant by CASing state and updating count.
* Note that step does not check for reentrant
* acquires, which is postponed to full version
* to avoid having to check hold count in
* the more typical non-reentrant case.
* 3. If step 2 fails either because thread
* apparently not eligible or CAS fails or count
* saturated, chain to version with full retry loop.
*/
Thread current = Thread.currentThread();
// 获取锁当前状态
int c = getState();
// 如果当前有线程获取了写锁,且不是当前线程,返回失败
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
// 获取当前读锁的数量,读状态存储在高位
// c >>> 16取高16位的值
int r = sharedCount(c);
// 是否阻塞判断
// 锁数量没有达到最大值
// 尝试CAS将状态修改为c+65536, 修改成功则获取锁
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
// 如果谁也没有获取过读锁
if (r == 0) {
// 第一个reader指向当前线程,读锁持有数量为1
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
// 如果当前线程再次获取到读锁,持有数量+1
firstReaderHoldCount++;
} else {
// 获取读锁的不是第一个线程,记录每个线程获取的次数,存到线程的ThreadLocalMap中
HoldCounter rh = cachedHoldCounter;
// 缓存为空 || 缓存的不是当前线程的读锁计数
if (rh == null || rh.tid != getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
// 缓存的是当前线程的读锁计数,而当前线程的读锁计数在上次release时被删除
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;
}
return 1;
}
// 循环尝试获取锁
return fullTryAcquireShared(current);
}
// 默认进入非公平锁代码段
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -8159625535654395037L;
final boolean writerShouldBlock() {
return false; // writers can always barge
}
final boolean readerShouldBlock() {
/* As a heuristic to avoid indefinite writer starvation,
* block if the thread that momentarily appears to be head
* of queue, if one exists, is a waiting writer. This is
* only a probabilistic effect since a new reader will not
* block if there is a waiting writer behind other enabled
* readers that have not yet drained from the queue.
*/
return apparentlyFirstQueuedIsExclusive();
}
}
// 这里返回false,则不进行阻塞
// 如果头节点为空
// 如果头结点不为空,但头结点后面节点为空
// 如果头结点不为空,后继节点不为空,后继节点是共享的
// 如果头结点不为空,后继节点不为空,后继节点不是共享的,后继节点中线程为空
final boolean apparentlyFirstQueuedIsExclusive() {
Node h, s;
return (h = head) != null &&
(s = h.next) != null &&
!s.isShared() &&
s.thread != null;
}
/**
* Full version of acquire for reads, that handles CAS misses
* and reentrant reads not dealt with in tryAcquireShared.
*/
final int fullTryAcquireShared(Thread current) {
/*
* This code is in part redundant with that in
* tryAcquireShared but is simpler overall by not
* complicating tryAcquireShared with interactions between
* retries and lazily reading hold counts.
*/
HoldCounter rh = null;
for (;;) {
int c = getState();
// 有线程获取写锁,且不是当前线程返回失败
if (exclusiveCount(c) != 0) {
if (getExclusiveOwnerThread() != current)
return -1;
// else we hold the exclusive lock; blocking here
// would cause deadlock.
// 读线程需要阻塞
} else if (readerShouldBlock()) {
// Make sure we're not acquiring read lock reentrantly
// 当前线程占有了锁
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
} else {
// 其它线程占有了锁
if (rh == null) {
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current)) {
rh = readHolds.get();
// 当前线程的读锁计数为0
if (rh.count == 0)
// 在线程局部变量中删除当前线程的读锁计数
readHolds.remove();
}
}
// 当前线程的读锁计数为0
if (rh.count == 0)
// 应排队取锁
return -1;
}
}
// 读锁达到最大值,异常
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// 尝试CAS更新状态,成功则返回
if (compareAndSetState(c, c + SHARED_UNIT)) {
if (sharedCount(c) == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
if (rh == null)
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;
cachedHoldCounter = rh; // cache for release
}
return 1;
}
}
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
// 尝试释放读锁
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 (;;) {
// CAS失败将回到此处
int c = getState();
// 读锁计数--
int nextc = c - SHARED_UNIT;
// CAS重置读锁status
if (compareAndSetState(c, nextc))
// Releasing the read lock has no effect on readers,
// but it may allow waiting writers to proceed if
// both read and write locks are now free.
// CAS(state)成功
return nextc == 0;
}
}
获取写锁
// WriteLock
public void lock() {
sync.acquire(1);
}
// AQS
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
// Sync
protected final boolean tryAcquire(int acquires) {
/*
* Walkthrough:
* 1. If read count nonzero or write count nonzero
* and owner is a different thread, fail.
* 2. If count would saturate, fail. (This can only
* happen if count is already nonzero.)
* 3. Otherwise, this thread is eligible for lock if
* it is either a reentrant acquire or
* queue policy allows it. If so, update state
* and set owner.
*/
Thread current = Thread.currentThread();
// 获取当前锁的状态
int c = getState();
// 获取写锁的次数
int w = exclusiveCount(c);
if (c != 0) {
// (Note: if c != 0 and w == 0 then shared count != 0)
// 当前线程不是获取写锁的线程 或者有线程获取到读锁
if (w == 0 || current != getExclusiveOwnerThread())
return false;
// 写锁数量大于最大值,抛异常
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// Reentrant acquire
// 当前线程获取写锁
// ??? 当前线程已经获取写锁,且没有其它线程获取到读锁
setState(c + acquires);
return true;
}
// 写锁未被任何线程获取,CAS成功
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);
return true;
}
static final int SHARED_SHIFT = 16;
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
// 同步状态的低16位用来表示写锁的获取次数
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
// 1 & ((1<<16)-1)
// 同步状态的高16位用来表示读锁被获取的次数
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
// 2>>> 16
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;
}