Use 1.

1.1 Define a secure list collection

public class LockDemo  {
ArrayList<Integer> arrayList = new ArrayList<>();// Define a collection
// Define read locks
ReentrantReadWriteLock.ReadLock readLock = new    ReentrantReadWriteLock(true).readLock();
// Define write lock
ReentrantReadWriteLock.WriteLock writeLock = new ReentrantReadWriteLock(true).writeLock();

public void addEle(Integer ele) {
writeLock.lock(); // Get the write lock
arrayList.add(ele);
writeLock.unlock(); // Release the write lock
}
public Integer getEle(Integer index) {
try{
readLock.lock(); // Get read lock
Integer res = arrayList.get(index);
return res;
} finally{
readLock.unlock();// Release the read lock}}}Copy the code

The properties and methods in the 1.2 Sync source code were covered in the previous article

2. Get write lock source code analysis

ReentrantReadWriteLock Lock method

public void lock(a) {
sync.acquire(1);
}
Copy the code

The acquire AbstractQueuedSynchronizer method

public final void acquire(int arg) {
    If the lock fails to be acquired, the lock is queued
if(! tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }Copy the code

AcquireQueued (addWaiter(Node.exclusive), ARg))****, both the acquireQueued and addWaiter methods have been explained in detail in previous articles.

ReentrantReadWriteLock tryAcquire method

protected final boolean tryAcquire(int acquires) {
    // Get the current thread
    Thread current = Thread.currentThread();
    // Get the status
    int c = getState();
    // Counting the number of writer threads is the number of exclusive locks that can be accessed
    int w = exclusiveCount(c);
    // Current synchronization status state! If = 0, another thread has acquired the read or write lock
    if(c ! =0) {
       If the write lock status is 0, the read lock is occupied.
       // Returns false if the write lock status is not 0 and the write lock is not held by the current thread
        if (w == 0|| current ! = getExclusiveOwnerThread())return false;
       // Determine whether the same thread acquires the write lock more than the maximum number of times (65535). Reentrant is supported
        if (w + exclusiveCount(acquires) > MAX_COUNT)
            throw new Error("Maximum lock count exceeded");
         // Update the status
         // The current thread already holds the write lock. Now it is reentrant, so you only need to change the number of locks
        setState(c + acquires);
        return true;
    }
      If c=0, neither the read lock nor the write lock has been acquired
      //writerShouldBlock indicates whether it is blocked
    if(writerShouldBlock() || ! compareAndSetState(c, c + acquires))return false;
        // Set the lock to be owned by the current thread
    setExclusiveOwnerThread(current);
    return true;
}
static final class FairSync extends Sync {
// Whether the write lock should be blocked
    final boolean writerShouldBlock(a) {
returnhasQueuedPredecessors(); }}Copy the code

3. Obtain the flowchart of write lock

3.1 Flow Chart Obtaining write lock process

3.2 Flowchart analysis of the write lock process

The process of acquiring write locks is as follows:

  1. First, get c and w. C indicates the current lock status. W is the number of writer threads. Then check whether the synchronization state is 0. If the state! If =0, another thread has acquired the read or write lock.
  2. If the lock state is not zero (c! W = 0, w = 0, w = 0, w = 0, w = 0, w = 0 Or the lock state is not zero and the write lock state is not zero, but the thread that obtains the write lock is not the current thread, so the current thread cannot acquire the write lock.
  3. Check whether the current thread has acquired the write lock for more than the maximum number of times. If so, throw the exception, otherwise update the synchronization status (at this time, the current thread has acquired the write lock, the update is thread-safe), return true.
  4. If the state is 0, the read or write locks lock is not available, determine whether to block (fair and not fair way to achieve different), under the fair strategy always will not be blocked, under a fair strategy will judge, judge whether there is a waiting time synchronization the queue longer threads, if any, you may need to be blocked, otherwise, no obstruction), If no blocking is required, the CAS updates the synchronization status. On success, the CAS returns true, on failure, the lock was seized by another thread, and false. Also return false if blocking is required.
  5. After the write lock is successfully acquired, the current thread is set to own the write lock, returning true.
  6. If the lock fails to be acquired, the current thread is placed on a blocking queue.

Release write lock source code analysis

ReentrantReadWriteLock Unlock method

public void unlock(a) {
    sync.release(1);
}
Copy the code

AbstractQueuedSynchronizer the release method

public final boolean release(int arg) {
    // If true is returned, the release is successful
    if (tryRelease(arg)) {
        Node h = head;
        Wake up subsequent threads if the header is not empty and the waitStatus of the head node is wake up
        if(h ! =null&& h.waitStatus ! =0)
         // Wake up the subsequent thread
            unparkSuccessor(h);
        return true;
    }
    return false;
}
Copy the code

TryRelease method in ReentrantReadWriteLock

protected final boolean tryRelease(int releases) {
// If the lock holder is not the current thread, throw an exception
    if(! isHeldExclusively())// Invalid monitor exception
        throw new IllegalMonitorStateException();
        // Count the number of new threads writing locks
    int nextc = getState() - releases;
    // If the exclusive mode reentrant value is 0, the exclusive mode is released
    boolean free = exclusiveCount(nextc) == 0;
    if (free)
     // Set the exclusive thread to null
        setExclusiveOwnerThread(null);
    // Set the number of new threads to write locks
    // Update the exclusive reentrant regardless of whether the exclusive mode is released
    setState(nextc);
    return free;
}
protected final boolean isHeldExclusively(a) {
    // Return true if the current thread is the thread holding the current lock
    return getExclusiveOwnerThread() == Thread.currentThread();
}
Copy the code

5. Release write lock flowchart

5.1 Flowchart Release process

5.2 Flowchart release process analysis

Write lock release process:

  1. First check to see if the current thread is the holder of the write lock, if not throw an exception. Then check whether the number of threads writing the lock after release is 0. If it is 0, it indicates that the lock is free. Releasing the lock resource sets the thread holding the lock to NULL, otherwise releasing the lock is only a re-entry, and cannot empty the thread writing the lock.
  2. Note: This method is used to release write lock resources. First, it will determine whether the thread is an exclusive thread. If it is not, an exception will be thrown.

6. Summary

6.1 the state analysis

private volatile int state;
Copy the code

Int occupies 4 bytes and 8 bits per byte, so state is a 32 bit, 16 bits higher for read locks and 16 bits lower for write locks.

// 0x0000FFFF hexadecimal // 1111111111111111111111 2 base // 65535 10 base static final int SHARED_SHIFT = 16; static final int SHARED_UNIT = (1 << SHARED_SHIFT); // 65536 static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1; //65535 // 1111111111111111 static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1; / / 65535 / / 1111111111111111Copy the code

If the status bit C is synchronized at this time, obtain the write state C & EXCLUSIVE_MASK If the status bit C is synchronized at this time, obtain the read state C >>>16 Unsigned complement 0, move 16 bits right

6.2 pay attention to

This is ReentrantReadWriteLock’s write lock analysis. The next post will be Condition*** analysis. If there is any error, please kindly point it out and correct it.