The second ReadWriteLock
ReadWriteLock ReadWriteLock ReadWriteLock ReadWriteLock ReadWriteLock ReadWriteLock ReadWriteLock
1. hasQueuedPredecessors
In the previous article, there was a judgment in the process of obtaining and reading shared locks,
if(! readerShouldBlock() &&Copy the code
If readerShouldBlock returns false then the lock is acquired normally, if true then the lock is acquired
Here is the content of the fair lock method:
// ReentrantReadWriteLock.FairSync#readerShouldBlock
final boolean readerShouldBlock(a) {
return hasQueuedPredecessors();
}
/ / determine
Return true if a thread queued before the current thread acquired the lock, i.e. the queue already has elements but is not itself.
// Otherwise return false (no queue)
public final boolean hasQueuedPredecessors(a) {
Node t = tail; // Queue tail pointer
Node h = head;// Queue header pointer
Node s;// Temporary variables
returnh ! = t &&// compare head tail if the queue is empty h! = t to false
((s = h.next) == null || // next of head is empty to prove that queue is emptys.thread ! = Thread.currentThread()// If head has next, which is the first waiting thread to determine if it is itself, then hey hey
);
}
Copy the code
2. What can be said about a series of Settings after acquiring the lock
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++;
}
Copy the code
FirstReader: Records the first thread to acquire the read lock
FirstReaderHoldCount: Records the number of times the first thread to acquire the read lock acquired the lock
private transient Thread firstReader = null;/ / thread
private transient int firstReaderHoldCount;/ / the number of
Copy the code
CachedHoldCounter: Records the thread ID+ times
Store it in a ThreadLocal.
Each thread that acquired the read lock is stored
static final class HoldCounter {
int count = 0;
// Use id, not reference, to avoid garbage retention
final long tid = getThreadId(Thread.currentThread());
}
Copy the code
ReadHolds: classes that inherit from ThreadLocal
static final class ThreadLocalHoldCounter
extends ThreadLocal<HoldCounter> {
// initialValue is defined
This function is called the first time ThreadLocal initializes a map
public HoldCounter initialValue(a) {
return newHoldCounter(); }}Copy the code
Summary: store all threads + times that acquire read locks
I don’t know why it is stored like this. Maybe it is the same as why HashMap was used in the past. I don’t know…
3. Take a look at the release process of read locks
ReadWriteLock rw = new ReentrantReadWriteLock();
rw.readLock().unlock();
Copy the code
ReentrantReadWriteLock#tryReleaseShared:
// AQS#releaseShared
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
// If true is returned, the current thread has no read lock
// Doing a doReleaseShared operation can simply be interpreted as waking up another waiting thread (the next waiting thread in the queue)
doReleaseShared();
return true;
}
return false;
}
protected final boolean tryReleaseShared(int unused) {
// Get the current thread
Thread current = Thread.currentThread();
// Check whether firstReader is used by the current thread
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
Void firstReader if firstReaderHoldCount equals 1
// The lock is acquired once
if (firstReaderHoldCount == 1)
firstReader = null;
else
// Otherwise, subtract 1
firstReaderHoldCount--;
} else {
// If it is not the first thread to acquire the read lock
HoldCounter rh = cachedHoldCounter;
// Check whether cachedHoldCounter is the holder of the current thread. If not, get readHolds(ThreadLocal)
if (rh == null|| rh.tid ! = getThreadId(current)) rh = readHolds.get();// Determine the number of locks held
int count = rh.count;
// <=1 to remove a ThreadLocal variable, remember that ThreadLocal must be removed before it leaks
if (count <= 1) {
readHolds.remove();
if (count <= 0)
throw unmatchedUnlockException();
}
// If you hold a lot, subtract 1
--rh.count;
}
//
for (;;) {
// state-SHARED_UNIT
// SHARED_UNIT = (1 << SHARED_SHIFT) = 65536
int c = getState();
int nextc = c - SHARED_UNIT;
// cas sets the new value
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; }}//
private void doReleaseShared(a) {
//
for (;;) {
Node h = head;
// h ! = null && h ! = tail If true, there are waiting threads in the queue
if(h ! =null&& h ! = tail) {// Get waitStatus. WaitStatus is the status given to it by its successor thread
int ws = h.waitStatus;
// If the state is SIGNAL, wake up is required
if (ws == Node.SIGNAL) {
if(! compareAndSetWaitStatus(h, Node.SIGNAL,0))
continue; // loop to recheck cases
/ / wake
unparkSuccessor(h);
}
// If the state is 0 it doesn't need to be woken up at all and then the person who needs to be woken up later
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // 如果cas失败了 接着循环 loop on failed CAS
}
// If the head changes, the loop should continue
if (h == head) // loop if head changed
break; }}Copy the code
4. Pay attention to
Write these knowledge in order to throw brick, is not very perfect, in fact, you can write a method to follow the breakpoint, into the source code to see that it is easier to deepen the impression.
About write lock to obtain and release the reader friends to study it yourself have a question can give me a message we discuss together ha
Welcome to our official account: