ReentrantLock (reentrant lock)

Reentrant locks implemented based on AQS include fair and unfair implementation methods.

The difference between fair and unfair:

1. Unfair: Actively grab the lock, fail to grab the lock, enter the lock acquisition process implemented by AQS (queue)

2. Fair lock: Do not actively grab the lock and directly enter the AQS method of acquiring the lock (queuing up). This is also the difference between fair and unfair lock (actively trying to grab the lock).

Reentrancy is mainly reflected in the superposition of the resource state value when the same thread accesses the resource.

public class ReentrantLock implements Lock, java.io.Serializable {<!-- -->

    //Provide synchronizers for all implementation mechanisms
    private final Sync sync;

    /**
     * Inherited from the synchronizer base class of AQS, subclasses are divided into fair and unfair implementations. Use the state of AQS to represent the number of lock resources acquired.
     */
    abstract static class Sync extends AbstractQueuedSynchronizer {<!-- -->
        //Abstract method for acquiring locks, implemented by subclasses
        abstract void lock();

        //Methods for unfair lock acquisition
        final boolean nonfairTryAcquire(int acquires) {<!-- -->
            //Get the current thread
            final Thread current = Thread.currentThread();
            //Get the state value of AQS
            int c = getState();
            //Try to acquire the lock
            if (c == 0) {<!-- -->
                //cas continues to try to obtain
                if (compareAndSetState(0, acquires)) {<!-- -->
                    //Acquisition is successful, set the current thread that obtained the mutex lock
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            //If there is no lock resource, determine whether the current lock thread is itself. If so, enter the method. This is the main implementation of the reentrant idea.
            else if (current == getExclusiveOwnerThread()) {<!-- -->
                //Note: Why is there no CAS in the branch block here? Because when entering this method, the current thread is considered reentrant, which proves that the mutex lock has been added and there is no competition problem.
                //Use AQS state to record the number of reentrants
                int nextc = c + acquires;
                if (nextc < 0) // Beyond the range of int, it will become a negative number if it exceeds
                    throw new Error("Maximum lock count exceeded");
                setState(nextc); //Set AQS state value
                return true;
            }
            return false;
        }

        //Method to release lock resources (no distinction between fair and unfair methods)
        protected final boolean tryRelease(int releases) {<!-- -->
            int c = getState() - releases; //Subtract the released resource value from the original state
            if (Thread.currentThread() != getExclusiveOwnerThread())
                //The thread currently releasing resources is not the thread that acquired the lock, and an exception is thrown.
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {<!-- --> //Complete release successful, other threads can acquire the lock
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c); //Update state value
            return free;
        }
//Determine whether the lock is obtained
        protected final boolean isHeldExclusively() {<!-- -->
            return getExclusiveOwnerThread() == Thread.currentThread();
        }
//Create condition object
        final ConditionObject newCondition() {<!-- -->
            return new ConditionObject();
        }

        //Get the thread that acquires the lock
        final Thread getOwner() {<!-- -->
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }
//Get the number of lock resources (number of reentrants)
        final int getHoldCount() {<!-- -->
            return isHeldExclusively() ? getState() : 0;
        }

        final boolean isLocked() {<!-- -->
            return getState() != 0;
        }

        /**
         * Reconstitutes the instance from a stream (that is, deserializes it).
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {<!-- -->
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }

    //Synchronizer to implement unfair lock
    static final class NonfairSync extends Sync {<!-- -->
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * Performs lock. Try immediate barge, backing up to normal
         * acquire on failure.
         */
        //Get lock method
        final void lock() {<!-- -->
            //CAS sets the state value, which means grabbing the lock
            if (compareAndSetState(0, 1))
                //The lock grab is successful, set the mutex lock owning thread as the current thread
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1); //Failed to grab the lock, enter the lock acquisition process implemented by AQS
        }

        protected final boolean tryAcquire(int acquires) {<!-- -->
            //Call the unfair lock acquisition method provided by the parent class
            return nonfairTryAcquire(acquires);
        }
    }

    //Synchronizer to implement fair lock
    static final class FairSync extends Sync {<!-- -->
        private static final long serialVersionUID = -3000897897090466540L;

        final void lock() {<!-- -->
            //Do not actively grab the lock, directly enter the AQS method of acquiring the lock. This is also the difference between fair and unfair locks (actively trying to grab the lock)
            acquire(1);
        }

        //Get the implementation of the lock and the subclass implementation method of the hook function called by AQS
        protected final boolean tryAcquire(int acquires) {<!-- -->
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {<!-- -->
                //No other thread is locked, CAS grabs the lock
                if (!hasQueuedPredecessors() & amp; & amp; // Determine whether there are other threads queuing in the queue, if so, fail to acquire the lock
                    compareAndSetState(0, acquires)) {<!-- -->
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            //If other threads have already been locked, determine whether the locked thread is yourself. If it is yourself, the lock will be re-entered.
            else if (current == getExclusiveOwnerThread()) {<!-- -->
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }

    //The default constructor creates an unfair lock synchronizer
    public ReentrantLock() {<!-- -->
        sync = new NonfairSync();
    }
//Create fair and unfair lock synchronizers based on fair
    public ReentrantLock(boolean fair) {<!-- -->
        sync = fair ? new FairSync() : new NonfairSync();
    }
//Lock operation, call the sync synchronizer lock method
    public void lock() {<!-- -->
        sync.lock();
    }

    public void lockInterruptibly() throws InterruptedException {<!-- -->
        sync.acquireInterruptibly(1);
    }

    public boolean tryLock() {<!-- -->
        return sync.nonfairTryAcquire(1);
    }

    public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {<!-- -->
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
//Release the lock
    public void unlock() {<!-- -->
        sync.release(1);
    }

    //Get the AQS condition object
    public Condition newCondition() {<!-- -->
        return sync.newCondition();
    }
}