1. StampedLock characteristics
StampedLock is a new read-write lock for JDK 8. Unlike read-write locks, it is not implemented by AQS.Its state is a long variable, state is designed differently from read-write locks, provides three modes to control read/write acquisition, and implements its own synchronous wait queue internally.
1.1, StampedLock read-write lock
Write lock: Use the writeLock method to acquire a lock that will block when it is not available, and return a stamp corresponding to the write lock after successful acquisition. In the unlockWrite method, this stamp is required to release the corresponding lock.This stamp is also available in tryWriteLock.When a write lock is acquired in write mode, the read lock cannot be acquired, and all optimistic read lock validation (validate method) fails.
Read Lock: Use the readLock method to obtain a lock that will block when more resources are available (similar to the AQS state design).Similarly, stamp is returned after successful acquisition of the lock for the same purpose as described above.The same is true for tryReadLock.
Optimistic read lock: Obtained using the tryOptimisticRead method, an optimistic read lock can be successfully acquired only when a write lock is available, and a stamp will be returned after successful acquisition.The validate method can use this stamp to determine if a write lock has been acquired.This pattern can be understood as a weak version of a read-lock, which can be broken at any time.Optimistic read mode is often used in short read-only code segments to reduce contention and improve throughput.Optimistic reading areas should read only fields and save them in local variables for use after validation (the validate method).Field reads may be inconsistent in optimistic reading mode, so validate() may need to be called repeatedly to check consistency.For example, these steps are usually necessary when you first read an object or array reference and then access one of its fields, elements, or methods.
1.2, Transition of Three Modes
StampedLock can conditionally convert locks to each other.
Convert other locks to write locks tryConvertToWriteLock():
The current postmark is in write-lock mode and returns the current postmark directly.
If the current postmark is in read lock mode, the read lock is released, the write lock is acquired, and the write lock postmark is returned.
Current postmark holds optimistic lock, write lock is acquired immediately through CAS, write lock postmark is returned for success, 0 for failure;
Convert other locks to read locks tryConvertToReadLock:
If the current postmark is in write lock mode, the write lock is released, the read lock is acquired, and the read lock postmark is returned.
If the current postmark is in read lock mode, the current read lock postmark is returned directly.
The current postmark holds an optimistic lock, and if the read lock is acquired immediately through CAS, the read lock postmark is returned; otherwise, the acquisition failure returns 0;
Convert other locks to optimistic locks tryConvertToOptimisticRead:
If the current postmark holds a read or write lock, the read/write lock is released directly and the observed postmark value is returned.
The current postmark holds an optimistic lock. If the optimistic lock postmark is valid, the observer postmark is returned.
1.3. Application scenarios for StampedLock
StampedLock is generally an internal tool class for thread security.Its use depends on a certain understanding of the internal properties of data, objects, and methods.StampedLock is non-reentrant, so other parties trying to acquire a lock repeatedly cannot be called inside the lock.If a stamp has not been used or validated for a long time, validation may fail after a long time.StampedLocks is serializable, but it becomes initially unlocked after deserialization, so it is not safe in remote locking.
1.4. Equity of StampedLock
StampedLock's scheduling strategy does not always favor read or write threads. All "try" methods are acquired to the best of their ability and do not necessarily follow any scheduling or fair policies.When a lock acquired or converted from the'try'method fails to return 0, no lock status information is carried.Because StampedLock supports coordinated use across multiple lock modes, it does not directly implement the Lock or ReadWriteLock interfaces.However, if the application requires Lock-related functionality, it can return a Lock view through the asReadLock(), asWriteLock(), and asReadWriteLock() methods.
2. Source Code Analysis
2.1. Main attributes
//Gets the number of threads available to the CPU to determine the number of loops when spinning private static final int NCPU = Runtime.getRuntime().availableProcessors(); //Determine the limit on the number of spins based on NCPU (not necessarily this many times, because the actual code is random) private static final int SPINS = (NCPU > 1) ? 1 << 6 : 0; //Number of spins on the head node private static final int HEAD_SPINS = (NCPU > 1) ? 1 << 10 : 0; //Maximum number of spins on the head node private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 16 : 0; //Number of cycles waiting for spin lock overflow private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1 //Number of bit s used to read thread count before overflow private static final int LG_READERS = 7; //One Read Status Unit: 0000 0000 0001 private static final long RUNIT = 1L; //A write status unit: 0000 1000 0000 private static final long WBIT = 1L << LG_READERS; //Read Status Identification: 0000 0111 1111 private static final long RBITS = WBIT - 1L; //Maximum read lock count: 0000 0111 1110 private static final long RFULL = RBITS - 1L; //Mask for number of read and write threads: 0000 1111 1111 private static final long ABITS = RBITS | WBIT; ////Read the inverse of the number of threads, all 25 bits high are 1:1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 10000000 private static final long SBITS = ~RBITS; // note overlap with ABITS // Initial value of state private static final long ORIGIN = WBIT << 1; // Interrupt Identification private static final long INTERRUPTED = 1L; // Node status value, wait/cancel private static final int WAITING = -1; private static final int CANCELLED = 1; // Node mode, read/write mode private static final int RMODE = 0; private static final int WMODE = 1; //Head node of waiting queue private transient volatile WNode whead; //Waiting for the end node of the queue private transient volatile WNode wtail; // Lock state private transient volatile long state; ////Because the read state is only 7-bit small, this variable will be used to record when it exceeds 128 private transient int readerOverflow;
2.2, node implementation
//Node implementation waiting for queue static final class WNode { //Precursor Node volatile WNode prev; //Successor Node volatile WNode next; //Link list used by read threads volatile WNode cowait; // list of linked readers //Waiting Threads volatile Thread thread; // non-null while possibly parked //Node State volatile int status; // 0, WAITING, or CANCELLED //Node mode final int mode; // RMODE or WMODE WNode(int m, WNode p) { mode = m; prev = p; } }
2.3. State state implementation
state status description:
- Bit 0 - bit6 is the read lock count, and readerOverflow is the read lock count when RFULL (126) is exceeded.State adds RUINT when a read lock is acquired (value 1); state subtracts RUINT when a read lock is released.
- bit7 is a write lock identifier, with a value of 1 indicating that a write lock has been acquired and a value of 0 indicating that a read lock has been acquired.When a thread acquires or releases a write lock, it adds a state to WBIT;
- bit8 - bit64: Represents a write lock version whose value changes whether a write lock is acquired or released.
Initial state bit8 is 1, other bits are 0.
state Common Status Identification:
-
RUNIT:
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001 -
WBIT:
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1000 0000 -
RBITS:
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0111 1111 -
RFULL:
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0111 1110 -
ABITS:
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 1111 -
SBITS:
1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1000 0000 -
ORIGIN:
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001 0000 0000
State common state judgment:
- There is a wireless process to get write status: state < WBIT, true: none, false: yes;
- Read status overflow: (state & ABITS) < RFULL, true; no; false: yes;
- Get read status: state + RUNIT (or readerOverflow + 1)
- Get write status: state + WBIT
- Release read state: state - RUNIT (or readerOverflow - 1)
- Release Write State: (s += WBIT) == 0L? ORIGIN: s
- Is it a write lock: (state & WBIT)!= 0L
- Is it a read lock: (state & RBITS)!= 0L
2.4. Write lock acquisition and release
Acquire write lock:
public long writeLock() { long s, next; //(state & ABITS) Get the lower 8 bits to determine if a read/write lock exists. //For other read locks, bit0-bit6 is not zero, and for other write locks, bit7 is not zero. //So if there are other write locks or read locks, it will fail //Attempting CAS to acquire a write lock //Failed call acquireWrite to continue acquiring write locks return ((((s = state) & ABITS) == 0L && U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ? next : acquireWrite(false, 0L)); }
private long acquireWrite(boolean interruptible, long deadline) { //Node is the current node, p is the precursor of the current node WNode node = null, p; // First spin - mainly for team entry for (int spins = -1;;) { // spin while enqueuing long m, s, ns; //(state&ABITS) 0 means no read/write lock, try CAS to acquire write lock if ((m = (s = state) & ABITS) == 0L) { if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT)) return ns; } else if (spins < 0) // If the number of spins is less than 0, the number of spins is calculated // If a write lock (m == WBIT) is currently exclusive and the queue has no elements (wtail == whead), // Indicates that the precursor node of the current node is the node that acquires an exclusive lock and the lock will be released soon. // Just spin SPINS times, if it's not your turn to join the team // Otherwise, the number of spins is zero spins = (m == WBIT && wtail == whead) ? SPINS : 0; else if (spins > 0) { // When the number of spins is greater than 0, the current spin is randomly reduced by one spin if (LockSupport.nextSecondarySeed() >= 0) --spins; } else if ((p = wtail) == null) { // initialize queue // If the queue is not initialized, create a new empty node and initialize the header and tail nodes WNode hd = new WNode(WMODE, null); if (U.compareAndSwapObject(this, WHEAD, null, hd)) wtail = hd; } else if (node == null) // If the new node has not been initialized, create it and assign its preceding node to the tail node node = new WNode(WMODE, p); else if (node.prev != p) // If the precursor node of the new node is not the tail node, // The precursor node that updates the new node is the new tail node node.prev = p; else if (U.compareAndSwapObject(this, WTAIL, p, node)) { // If the attempt to update the new node to a new tail node succeeds, the loop exits p.next = node; break; } } // Second spin - mainly blocking and waiting to wake up for (int spins = -1;;) { // h is the head node, np is the front node of the new node, pp is the front node, ps is the state of the front node WNode h, np, pp; int ps; // If the head node equals the leading node, it's almost your turn if ((h = whead) == p) { if (spins < 0) // If the number of spins is less than 0, the number of initial spins is spins = HEAD_SPINS; else if (spins < MAX_HEAD_SPINS) // If the number of spins is less than the maximum number of spins of the head node, the number of spins is increased spins <<= 1; // Third spin, keep trying to acquire write locks for (int k = spins;;) { // spin at head long s, ns; //CAS acquires write locks without read-write locks and updates node information with success if (((s = state) & ABITS) == 0L) { if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT)) { whead = node; node.prev = null; return ns; } } // Random spin number, jump out of the loop and try again when the spin number is reduced to 0 else if (LockSupport.nextSecondarySeed() >= 0 && --k <= 0) break; } } //Is the header node empty? else if (h != null) { // help release stale waiters WNode c; Thread w; // If the cowait list (stack) of the header node is not empty, wake up all the nodes inside while ((c = h.cowait) != null) { if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) && (w = c.thread) != null) U.unpark(w); } } // If the header node does not change if (whead == h) { // Update if tail node changes if ((np = node.prev) != p) { if (np != null) (p = np).next = node; // stale } else if ((ps = p.status) == 0) // Update to WAITING if tail node status is 0 U.compareAndSwapInt(p, WSTATUS, 0, WAITING); else if (ps == CANCELLED) { // If the tail node is canceled, remove it from the list if ((pp = p.prev) != null) { node.prev = pp; pp.next = node; } } else { // Processing with timeout long time; // 0 argument to park means no timeout if (deadline == 0L) time = 0L; //Cancel node when time expires else if ((time = deadline - System.nanoTime()) <= 0L) return cancelWaiter(node, node, false); //Set Thread blocker Thread wt = Thread.currentThread(); U.putObject(wt, PARKBLOCKER, this); node.thread = wt; //1. The current precursor node state is WAITING; //2. The precursor node of the current node is not a header node or has a read-write lock already acquired; //3. Head node changes; //4. The precursor node of the current node has not changed; //Block the current node when all four conditions are met if (p.status < 0 && (p != h || (state & ABITS) != 0L) && whead == h && node.prev == p) U.park(false, time); // emulate LockSupport.park node.thread = null; //Set thread blocker to null U.putObject(wt, PARKBLOCKER, null); //Cancel node if current node 100 interrupts if (interruptible && Thread.interrupted()) return cancelWaiter(node, node, true); } } } }
Write lock release:
public void unlockWrite(long stamp) { WNode h; //Because write locks are exclusive locks, it is easy to judge the state!= stamp; //Or bit7 is 0, that is, stamp state is write-free if (state != stamp || (stamp & WBIT) == 0L) throw new IllegalMonitorStateException(); //Modify the state state, state += WBIT; overflow initializes to ORIGIN state = (stamp += WBIT) == 0L ? ORIGIN : stamp; //The head node is not empty and in normal state releases the lock on the head node if ((h = whead) != null && h.status != 0) release(h); }
private void release(WNode h) { if (h != null) { WNode q; Thread w; //Set header node status to 0 U.compareAndSwapInt(h, WSTATUS, WAITING, 0); //If the next node of the head node is empty or the state is CANCEL, it traverses forward from the tail node. //Find the first valid node after the header node (status 0 or WAITTING) if ((q = h.next) == null || q.status == CANCELLED) { for (WNode t = wtail; t != null && t != h; t = t.prev) if (t.status <= 0) q = t; } //Wake up the next valid node if (q != null && (w = q.thread) != null) U.unpark(w); } }
2.5. Read lock acquisition and release
Read lock acquisition:
public long readLock() { long s = state, next; // bypass acquireRead on common uncontended case //The synchronization queue is empty, the read lock count value does not exceed the maximum value (no write lock). If CAS acquires a lock successfully, the postmark value is returned directly. //Otherwise acquireRead acquires the read lock return ((whead == wtail && (s & ABITS) < RFULL && U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ? next : acquireRead(false, 0L)); }
private long acquireRead(boolean interruptible, long deadline) { WNode node = null, p; for (int spins = -1;;) { WNode h; //If the synchronization queue head node equals the tail node, there is no node or only one node in the queue //Then spin for a while and wait until the head node releases the lock to acquire it if ((h = whead) == (p = wtail)) { for (long m, s, ns;;) { //(state & ABITS) is less than RFULL, meaning no write lock, CAS acquires read lock directly; //Otherwise, if (state & ABITS) is less than WBIT, there is no write lock but the read lock count has overflowed. //CAS updates the read lock count to acquire a read lock if ((m = (s = state) & ABITS) < RFULL ? U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) : (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) return ns; //(state & ABITS) is greater than WBIT, indicating that the write lock has been occupied, then spin else if (m >= WBIT) { //Random spin reduction if (spins > 0) { if (LockSupport.nextSecondarySeed() >= 0) --spins; } else { //Have you not acquired a read lock yet after spinning? if (spins == 0) { WNode nh = whead, np = wtail; //Judge stability (whether modified), jump out of cycle if ((nh == h && np == p) || (h = nh) != (p = np)) break; } //Initialize spins spins = SPINS; } } } } //If spin acquisition fails, node initialization-related processing occurs //Initialize queue if tail node is empty if (p == null) { // initialize queue WNode hd = new WNode(WMODE, null); if (U.compareAndSwapObject(this, WHEAD, null, hd)) wtail = hd; } //Initialize the node representing the current read thread else if (node == null) node = new WNode(RMODE, p); //head==tail or queue tail.mode is not read, //Then add the node node of the current thread to the end of the queue and jump out of the outer loop else if (h == p || p.mode != RMODE) { if (node.prev != p) node.prev = p; else if (U.compareAndSwapObject(this, WTAIL, p, node)) { p.next = node; break; } } //If head!= tail indicates that a thread is already waiting in the queue or tail.mode l is a read state RMODE, //Then CAS adds the current thread's node node node to the tail node's cowait chain else if (!U.compareAndSwapObject(p, WCOWAIT, node.cowait = p.cowait, node)) node.cowait = null; else { for (;;) { WNode pp, c; Thread w; ////If the header is not empty then try to free the nodes in the cowait chain of the header if ((h = whead) != null && (c = h.cowait) != null && U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) && (w = c.thread) != null) // help release U.unpark(w); //If the precursor of the tail node is head or head==tail or the precursor of the tail node is null //That is, the node where the current node is located (because the node may be in the cowait chain) //The predecessor is the head or the head has been released as null if (h == (pp = p.prev) || h == p || pp == null) { long m, s, ns; do { //If no write state is occupied then spin attempts to get the read state and stamp is returned successfully if ((m = (s = state) & ABITS) < RFULL ? U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) : (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) return ns; } while (m < WBIT); } //Judging stability if (whead == h && p.prev == pp) { long time; //If tail's predecessor is null or head==tail or tail has been cancelled (p.status > 0) //Set the node directly as null to jump out of the loop and go back to the open for loop to try to get the synchronization status again if (pp == null || h == p || p.status > 0) { node = null; // throw away break; } if (deadline == 0L) time = 0L; //Cancel current thread if timeout occurs else if ((time = deadline - System.nanoTime()) <= 0L) return cancelWaiter(node, p, false); Thread wt = Thread.currentThread(); U.putObject(wt, PARKBLOCKER, this); node.thread = wt; //tail predecessor is not head er or only write threads are currently in sync state //Judging stability if ((h != pp || (state & ABITS) == WBIT) && whead == h && p.prev == pp) U.park(false, time); node.thread = null; U.putObject(wt, PARKBLOCKER, null); //Cancel if interrupted if (interruptible && Thread.interrupted()) return cancelWaiter(node, p, true); } } } } //If there are no nodes in the queue or tail's mode l is WMODE write state, //Then the node enters the loop after it is added to the tail queue for (int spins = -1;;) { WNode h, np, pp; int ps; //If P (the precursor node of a node) is the head, the spin mode attempts to get the synchronization state if ((h = whead) == p) { //First cycle, set the number of spins if (spins < 0) spins = HEAD_SPINS; //Spin number increase else if (spins < MAX_HEAD_SPINS) spins <<= 1; for (int k = spins;;) { // spin at head long m, s, ns; //Spin Attempt to Get Synchronization Status //If successful, set the node as head and free the node in the node's cowait chain and return stamp if ((m = (s = state) & ABITS) < RFULL ? U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) : (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) { WNode c; Thread w; whead = node; node.prev = null; while ((c = node.cowait) != null) { if (U.compareAndSwapObject(node, WCOWAIT, c, c.cowait) && (w = c.thread) != null) U.unpark(w); } return ns; } //Random--k controls the number of loops if a write thread gets synchronized (because a write thread may break in) else if (m >= WBIT && LockSupport.nextSecondarySeed() >= 0 && --k <= 0) break; } } //If the head is not null, free the nodes in the cowait chain of the head else if (h != null) { WNode c; Thread w; while ((c = h.cowait) != null) { if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) && (w = c.thread) != null) U.unpark(w); } } //Judging stability if (whead == h) { if ((np = node.prev) != p) { if (np != null) (p = np).next = node; // stale } //Attempt to set tail's state bit WAITING to indicate that there are waiting nodes behind else if ((ps = p.status) == 0) U.compareAndSwapInt(p, WSTATUS, 0, WAITING); //If tail has been canceled else if (ps == CANCELLED) { if ((pp = p.prev) != null) { node.prev = pp; pp.next = node; } } else { //Timeout determination long time; if (deadline == 0L) time = 0L; else if ((time = deadline - System.nanoTime()) <= 0L) return cancelWaiter(node, node, false); Thread wt = Thread.currentThread(); U.putObject(wt, PARKBLOCKER, this); node.thread = wt; //Blocking Wait if (p.status < 0 && (p != h || (state & ABITS) == WBIT) && whead == h && node.prev == p) U.park(false, time); node.thread = null; U.putObject(wt, PARKBLOCKER, null); //Interrupt handling if (interruptible && Thread.interrupted()) return cancelWaiter(node, node, true); } } } }
Read lock release:
public void unlockRead(long stamp) { long s, m; WNode h; for (;;) { //If the bit bit bit associated with the write count changes, or the bit associated with the read count is 0, or if there is a write lock, then the exception is if (((s = state) & SBITS) != (stamp & SBITS) || (stamp & ABITS) == 0L || (m = s & ABITS) == 0L || m == WBIT) throw new IllegalMonitorStateException(); //Read lock count not overflowing? if (m < RFULL) { if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) { if (m == RUNIT && (h = whead) != null && h.status != 0) release(h); break; } } //Read lock count overflow? else if (tryDecReaderOverflow(s) != 0L) break; } }
2.6, Optimistic Lock Acquisition
public long tryOptimisticRead() { long s; //When there is no write lock, it returns (state & SBITS), which is the high bit write count; //Otherwise, return 0, fail to get optimistic lock return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L; }
2.7. Conversion of lock mode
Convert to Write Lock: Convert locks in other modes such as Write, Read, Optimistic to Write
public long tryConvertToWriteLock(long stamp) { long a = stamp & ABITS, m, s, next; //Write lock status unchanged? while (((s = state) & SBITS) == (stamp & SBITS)) { //Currently no write/read lock?CAS Acquire Write Lock if ((m = s & ABITS) == 0L) { if (a != 0L) break; if (U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) return next; } //If there is a write lock and the state is unchanged, the original version postmark is returned directly else if (m == WBIT) { //Write thread is not the current thread?Error, jump out of the loop if (a != m) break; return stamp; } //No write lock, there is a read lock, that is, the current thread is the thread that acquires the read lock //Direct cas releases the read lock and acquires the write lock, state= (state - RUNIT + WBIT) else if (m == RUNIT && a != 0L) { if (U.compareAndSwapLong(this, STATE, s, next = s - RUNIT + WBIT)) return next; } //Spin waits for other read locks to release when other threads acquire them else break; } return 0L; }
Main Processing:
Write locks are acquired through CAS when the lock state is unread/write;
Returns the original postmark directly when the current thread has acquired a write lock;
When there is only one read lock, that is, when only the current thread acquires a read lock and no other read locks exist, CAS releases the read lock and acquires the write lock.
When the number of threads acquiring read locks is greater than 1, that is, when other threads besides the current thread acquire read locks, spin waits for other read locks to be released.
Convert to read lock: Convert read/write lock to read lock;
public long tryConvertToReadLock(long stamp) { long a = stamp & ABITS, m, s, next; WNode h; //No write lock? while (((s = state) & SBITS) == (stamp & SBITS)) { //No read/write lock, CAS acquires read lock if ((m = s & ABITS) == 0L) { //Wrong postmark?Exit Loop if (a != 0L) break; //Read lock count not overflowing? else if (m < RFULL) { if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) return next; } //Read lock count overflow? else if ((next = tryIncReaderOverflow(s)) != 0L) return next; } //Is there a write lock and the write lock is the current thread?Release the read lock and wake up subsequent write lock threads else if (m == WBIT) { //Write lock is not current thread, error, jump out of cycle if (a != m) break; state = next = s + (WBIT + RUNIT); if ((h = whead) != null && h.status != 0) release(h); return next; } //Has the current thread acquired a read lock? else if (a != 0L && a < WBIT) return stamp; else break; } return 0L; }
Main Processing:
CAS acquires a read lock if there is no read/write lock;
If the write lock is the current thread, CAS releases the write lock and acquires the read lock.
Returns the original postmark if the current thread has acquired a read lock;
Convert to Optimistic Lock:
public long tryConvertToOptimisticRead(long stamp) { long a = stamp & ABITS, m, s, next; WNode h; U.loadFence(); for (;;) { //Write Lock State Change? if (((s = state) & SBITS) != (stamp & SBITS)) break; //No read/write lock?Return directly to state if ((m = s & ABITS) == 0L) { if (a != 0L) break; return s; } //Write lock acquired?Release the write lock directly else if (m == WBIT) { if (a != m) break; state = next = (s += WBIT) == 0L ? ORIGIN : s; if ((h = whead) != null && h.status != 0) release(h); return next; } //Is the state unread or write-free? else if (a == 0L || a >= WBIT) break; //Read Lock Count Not Overflowed else if (m < RFULL) { if (U.compareAndSwapLong(this, STATE, s, next = s - RUNIT)) { if (m == RUNIT && (h = whead) != null && h.status != 0) release(h); return next & SBITS; } } //Read lock count overflow? else if ((next = tryDecReaderOverflow(s)) != 0L) return next & SBITS; } return 0L; }
Main Processing:
If the current thread has acquired a write lock, the write lock is released directly.
If the current thread has acquired a read lock, CAS releases the read lock.
Returns the state value when locked;