Java knowledge learning 13 (AQS detailed explanation)

1. Introduction to AQS?

The full name of AQS AbstractQueuedSynchronizertranslates to Abstract Queue Synchronizer . This class is java.util.concurrent.locksunder the package.

AQS is an abstract class, mainly used to build locks and synchronizers .

public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable {
    
    
}

AQS provides the implementation of some common functions for building locks and synchronizers. Therefore, using AQS can easily and efficiently construct a large number of widely used synchronizers , such as we mentioned ReentrantLock, Semaphore, others such as ReentrantReadWriteLock, SynchronousQueueetc. are based on AQS's.

2. AQS principle?

The core idea of ​​AQS The core idea of ​​AQS is: if the requested shared resource is idle, set the thread currently requesting the resource as an effective worker thread, and set the shared resource to a locked state. If the requested shared resource is occupied, a mechanism for thread blocking and waiting and lock allocation when awakened is required. This mechanism AQS is implemented based on CLH locks (Craig, Landin, and Hagersten locks).

The CLH lock is an improvement on the spin lock. It is a virtual two-way queue in bold style (a virtual two-way queue means that there is no queue instance, only the association relationship between nodes), and the thread that cannot acquire the lock temporarily will be added to the queue . AQS encapsulates each thread that requests shared resources into a node ( ) of a CLH queue lockNode to implement lock allocation. In CLH queue lock, a node represents a thread , which saves the reference of the thread ( thread), the state of the current node in the queue ( waitStatus), the predecessor node ( prev), and the successor node ( next).

The CLH queue lock structure is shown in the following figure:

insert image description here

The core schematic diagram of AQS (AbstractQueuedSynchronizer):
insert image description here

AQS uses the int member variable to indicate the synchronization state, and completes the queuing work of the resource thread statethrough the built-in thread waiting queue .

stateThe variable is volatilemodified by to display the lock status of the current critical resource.

// 共享变量,使用volatile修饰保证线程可见性
private volatile int state;

In addition, the status information statecan be manipulated by protectedthe type getState()、setState()and . compareAndSetState()Moreover, these methods are finalmodified and cannot be overridden in subclasses .

//返回同步状态的当前值
protected final int getState() {
    
    
     return state;
}
 // 设置同步状态的值
protected final void setState(int newState) {
    
    
     state = newState;
}
//原子地(CAS操作)将同步状态值设置为给定值update如果当前同步状态的值等于expect(期望值)
protected final boolean compareAndSetState(int expect, int update) {
    
    
      return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

Take ReentrantLockfor example , statethe initial value is 0, which means unlocked. When A thread lock(), will call tryAcquire()exclusively the lock and will state+1. After that, other threads will fail again , and other threads will not have the opportunity to acquire the lock until tryAcquire()thread A unlock()arrives (that is, the lock is released).state=0

Of course, before the lock is released, the A thread itself can acquire the lock repeatedly ( stateit will accumulate), which is the concept of reentrancy . But pay attention to how many times you need to release it, so as to ensure that stateit can return to the zero state.

Taking again CountDownLatchas an example, the task is divided into N sub-threads to execute, stateand it is also initialized to N (note that N must be consistent with the number of threads). The N sub-threads are executed in parallel, and will be decremented by 1 countDown()after each sub-thread is executed . After all sub-threads are executed (that is, state=0), the main calling thread will be called, and then the main calling thread will return from the function to continue the rest of the action.stateCAS(Compare and Swap)unpark()await()

Guess you like

Origin blog.csdn.net/ldy007714/article/details/130329915