“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.