声明对象方式
//构造方法传boolean以声明公平or非公平锁(非公平吞吐量大于公平)
ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock();
ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();
writeLock.lock();
readLock.lock();
源码简要分析
/*
* 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 */
//右移16位,显然返回高16位,即读锁(共享)的被持有数
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
/** Returns the number of exclusive holds represented in count */
//即state & (1,00000000,00000000-1) 显然低位全部为1,高16位全为0,所以可以计算出是否写锁已被持有
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
读锁获取
/**
* Acquires the read lock.
*
* 如果写锁没有被别的线程持有,将立刻获取读锁且立刻返回
* <p>Acquires the read lock if the write lock is not held by
* another thread and returns immediately.
*
如果写锁被背的线程持有,则当前线程将无法被调起处于休眠状态直到读锁被获取
lies dormant :处于休眠
* <p>If the write lock is held by another thread then
* the current thread becomes disabled for thread scheduling
* purposes and lies dormant until the read lock has been acquired.
*/
public void lock() {
sync.acquireShared(1);
}
/**
* Acquires in shared mode, ignoring interrupts. Implemented by
* first invoking at least once {@link #tryAcquireShared},
* returning on success. Otherwise the thread is queued, possibly
* repeatedly blocking and unblocking, invoking {@link
* #tryAcquireShared} until success.
*
*以共享模式获取,忽略中断。通过首先调用至少一次tryAcquireShared来实现,成功返回。否则线程排队,
*可能重复阻塞和解除阻塞,调用tryAcquireShared直到成功
*/
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
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
* 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();
//如果当前写锁已被持有,且持有写锁线程不为该线程,则直接返回-1
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
//获取读锁的被持有数
int r = sharedCount(c);
//如果当前读锁获取不需要阻塞,且被持有数量小于最大可持有数,且state可正常CAS计算,则返回1
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
if (r == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
// 除第一个线程之后的其他线程获得读锁
// 每个线程每次获得读锁重入计数+1
// readHolds 就是一个ThreadLocal,里面放的HoldCounter,用来统计每个线程的重入次数
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);
}
//AQS-查看获取读锁是否应该阻塞
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
//true:需要阻塞 false:不需阻塞
public final boolean hasQueuedPredecessors() {
Node t = tail;
Node h = head;
Node s;
//若头结点不等于尾结点则表示存在节点于头尾之间,即正在排队的节点线程
//如果h.next为空(表示已有线程先于该线程排队)则需要排队
//若下一个节点仍不是当前线程,则需要排队;反之不需要排队
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
//读锁添加失败就进入到这里,进入阻塞队列,同时再次尝试获取读锁
private void doAcquireShared(int arg) {
//addWaiter参数为节点为共享模式flag,含义为:Marker to indicate a node is waiting in shared mode
// addWaiter()方法中如果是首次进会调用enq(node)来完成初始化,否则就将共享节点添加到队列的尾部,并且返回这个共享节点
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
// 开始自旋
for (;;) {
// 获取到当前共享节点的前一个节点
final Node p = node.predecessor();
// 如果当前共享节点的前一个节点是head节点,也就是sentinel哨兵节点,就会尝试获取到读锁
if (p == head) {
// 再次尝试获取到读锁 成功是1,不成功是-1,也影响着下面的判断。
int r = tryAcquireShared(arg);
// 如果再次尝试获取读锁成功就执行下面代码,失败就往下走。
if (r >= 0) {
// 这里是尝试获取成功,则重新设置HEAD(将head节点指向当前节点,意思就是当前节点当sentinel哨兵节点了)
// 并且对于共享节点还有一个任务就是唤醒后面的共享节点,所以当前节点后面如果是读锁也会被唤醒,所以也就是读读并发。
setHeadAndPropagate(node, r);
// 将之前的head节点,也就是sentinel哨兵节点的next指向null,所以此节点没有任何引用了,就被回gc回收
p.next = null; // help GC
// 判断是否是被打断醒来的。
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
// 到这里就代表前面的尝试获取读锁失败了
// shouldParkAfterFailedAcquire()方法将当前节点的前一个节点的waitState标志位设为-1
// 但是设置的过程还是自旋一次尝试获取锁
// parkAndCheckInterrupt()方法是将当前线程park休眠。
// 当前线程park之前,总共是经历过3次尝试获取读锁。
// 注意等unLock()方法执行了就会从这里唤醒线程。所以还是在自旋中。醒来又会去尝试获取锁
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
读锁释放
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
//如果last firstReader = current,则递减计数器(若仅重入一次,则回收对象以释放内存)
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
if (firstReaderHoldCount == 1)
firstReader = null;
else
firstReaderHoldCount--;
} else {
//获取cachedHoldCounter(为上一次获取读锁的线程对象,因为往往获取锁后,紧接着就是释放,这样做缓存可以避免查找)
HoldCounter rh = cachedHoldCounter;
//获取rh正确引用以得到hold count
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();
//上文已经提到过,读锁为高16位,故count--操作不简单的视为-1,必须转换为1<<16以达到减一操作
int nextc = c - SHARED_UNIT;
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.
return nextc == 0;
}
}