Introduction to the
ReentrantReadWriteLock also relies on AQS to reenter read and write locks. ReentrantReadWriteLock has a read lock and a write lock. ReentrantReadWriteLock has a read lock and a write lock. ReentrantReadWriteLock has a read lock and a write lock.
ReentrantReadWriteLock
The ReadLock ReadLock() and WriteLock WriteLock() can be accessed by multiple reader threads at the same time. However, when accessed by the writer thread, both the reader and writer threads are blocked. Read/write lock features: fairness, reentrancy, and lock degradation
Write lock acquisition and release
A write lock is an exclusive lock that supports reentry, and its core acquisition method is:
Protected final Boolean tryAcquire(int acquires) {tryAcquire current = thread.currentThread (); Int c = getState(); // Obtain ReentrantReadWriteLock synchronization status int c = getState(); Int w = exclusiveCount(c); If (c! = 0) { // c ! = 0 && w = = 0 when being read or write lock lock hold thread not the current thread, failed to get write locks the if (w = = 0 | | current! = getExclusiveOwnerThread()) return false; If (w + exclusiveCount(acquires) > MAX_COUNT) throw new Error("Maximum lock count exceeded"); // Set the synchronization state setState(c + acquires); return true; } / / equity and justice, synchronous queue if there is a node, at the same time the state of cas set the if (writerShouldBlock () | |! compareAndSetState(c, c + acquires)) return false; // Set the thread to acquire the lock to the current thread setExclusiveOwnerThread(current); return true; }Copy the code
We can see from the source getState () to obtain the read and write locks total sync, then through exclusiveCount () method to obtain alone write lock synchronization state
static final int SHARED_SHIFT = 16;
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
static int exclusiveCount(int c) {
return c & EXCLUSIVE_MASK;
}
Copy the code
ReentrantReadWriteLock Cuts the state variable by bit. The lower 16 bits of the synchronization state indicate the number of write locks obtained, and the higher 16 bits indicate the number of read locks obtained
So this explains why write locks can be acquired up to 65535 times
The general idea of acquiring a write lock is as follows: If the read lock has been acquired by the read thread or the write lock has been acquired by another write thread, the write lock fails to be acquired. Otherwise, the write lock synchronization status can be added to the write lock synchronization status
Protected final Boolean tryRelease(int releases) {// Releases the thread that is not the lock holder if (! isHeldExclusively()) throw new IllegalMonitorStateException(); Int nexTC = getState() -releases; // Re-releases the synchronization state int nexTC = getState() -releases; Boolean Free = exclusiveCount(nexTC) == 0; if (free) setExclusiveOwnerThread(null); // Update the synchronization state setState(nexTC); return free; }Copy the code
Read lock acquisition and release
Read lock As opposed to write lock (exclusive or exclusive), a read lock is a reentrant shared lock that can be acquired by multiple threads at the same time. When no other writer thread is accessing it (or the write state is zero), the read lock will always be acquired successfully, and all it does is (thread-safe) increase the read state
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 sets the read lock state if (! ReaderShouldBlock () &&r < MAX_COUNT &&compareAndSetState (c, c + SHARED_UNIT)) { FirstReader = firstReaderHoldCount if (r == 0) {firstReader = current; firstReaderHoldCount = 1; FirstReaderHoldCount reentrant + 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); }Copy the code
Read locks to get the whole idea
final int fullTryAcquireShared(Thread current) { HoldCounter rh = null; for (;;) { int c = getState(); If (exclusiveCount(c)! = 0) { if (getExclusiveOwnerThread() ! = current) return -1; 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(); if (rh.count == 0) readHolds.remove(); } } if (rh.count == 0) return -1; If (sharedCount(c) == MAX_COUNT) throw new Error("Maximum lock count exceeded"); If (compareAndSetState(c, c + SHARED_UNIT)) { FirstReaderHoldCount (sharedCount(c) == 0) {firstReader = current; firstReaderHoldCount = 1; FirstReaderHoldCount reentrant + 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; }}}Copy the code
protected final boolean tryReleaseShared(int unused) { Thread current = Thread.currentThread(); If (firstReader == current) {// If (firstReader == current) { If (firstReaderHoldCount == 1) firstReader = null; FirstReaderHoldCount -1 else firstReaderHoldCount--; } else {// Update the number of times the current thread gets the lock 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; } // Spin CAS update read lock synchronization status for (;;) { int c = getState(); int nextc = c - SHARED_UNIT; if (compareAndSetState(c, nextc)) return nextc == 0; }}Copy the code
static final class HoldCounter { int count = 0; final long tid = getThreadId(Thread.currentThread()); }
static final class ThreadLocalHoldCounter extends ThreadLocal<HoldCounter> { public HoldCounter initialValue() { return new HoldCounter(); } } private transient HoldCounter cachedHoldCounter; private transient int firstReaderHoldCount; private transient Thread firstReader = null; Copy the code
Copy the code
Lock down
Lock degradation refers to the degradation of a write lock to a read lock, that is, the process of obtaining the write lock first and then releasing the write lock to ensure data visibility. Assume that there are two threads A and B. If thread A obtains the write lock, it directly releases the write lock instead of obtaining the read lock, and thread B obtains the write lock and modiifies the data, thread A cannot know the data update of thread B. If thread A acquires the read lock, that is, following the lock degradation step, thread B will be blocked until thread A uses the data and releases the read lock, and thread B can acquire the write lock to update the data.
conclusion
When another thread acquires the read lock, no other thread is allowed to acquire the write lock. When another thread acquires the write lock, no other thread is allowed to acquire the read lock and write lock. The write lock can be degraded to a read lock, and the read lock cannot be upgraded to a write lock
Thank you
The Art of Concurrent Programming in Java http://cmsblogs.com/?p=2213