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(); } }