“This is the third day of my participation in the Gwen Challenge in November. Check out the details: The last Gwen Challenge in 2021.”

The three core variables of AQS are state and queue blocking. Resources can be controlled through these three core variables.

Aqs core structure is shown below:

Description:

The condition queue is described as either a blocked queue or a condtion queue

Lock The queue that needs to queue for the lock is described below as: wait queue

Because of the semantic conflict, just distinguish between the two queues. The difference is that one is a two-way list and one is a one-way list.

ReentrantLock

Lock

ReentrantLock is divided into two modes: fair and unfair, which are not quite the same as the lock grab process.

The specific process is as follows:

The process of obtaining locks

ReentrantLock lock = new ReentrantLock(); 
lock.lock()// The process of obtaining the lock
Copy the code

Not fair lock

Path: Java. Util. Concurrent. The locks. Already. NonfairSync#lock 
final void lock(a) {
if (compareAndSetState(0.1))
setExclusiveOwnerThread(Thread.currentThread());
else acquire(1);
}
Copy the code

Explanation: When the unfair lock is entered for the first time, the CAS will first set the state value. If the setting is successful, the lock will be obtained. If the setting fails, the lock will be acquired.

Fair lock

Path: Java. Util. Concurrent. The locks. Already. FairSync#lock
final void lock(a) {
acquire(1);
}
Copy the code

Explanation: We found that the fair lock did not go to CAS at the beginning of the process, but it is normal to go through the acquire() process.

acquire

public final void acquire(int arg) {
Return true if (! = true if (! = true if (! = true if (! tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
// Interrupt thread sets interrupt bit
} 
1The first step is to go to the gun lock first, if successful directly exit, if the failure of the second step2What must the thread do if it fails to acquire the lock? AddWaiter (node.exclusive) is used to create a Node. TryAcquire () is used to manage a newly created NodeCopy the code

The following code follows the acquire() process.

Non-fair lock/fair lock tryAcquire()

// Unfair lock
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState(); // Get the status
if (c == 0) { // If it is 0, grab it
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current); return true; }}//state is not 0. The lock is not released and is the thread owner state+1
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires; setState(nextc);
return true; 
} 
return false;
}
/ / fair lock
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread(); 
int c = getState(); 
if (c == 0) { 
// Check whether there are any related threads in the queue node is already queued. Return true if the thread needs to be queued, false if it does not.
if(! hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current);
return true; }}else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires; 
setState(nextc);
return true;
} 
return false; }}Copy the code

Conclusion: Obtain the value of state first. If it is 0, it indicates that no thread has acquired the lock. Set state directly through CAS. Otherwise, the lock will fail to be acquired. Difference: When state==0, the unfair lock will directly grab the lock, while the fair lock will first check that there are nodes in the waiting queue. If there are threads waiting to acquire the lock, they will directly queue up behind and do not participate in the gun lock.

After the above failure to acquire the lock, the addWork() process is entered, which is designed to store the thread that has acquired the lock conflict in a wait queue, waiting for the previous node to wake up.