In-depth understanding of AQS and synchronized in java

Base

1 What is the principle of synchronized: What is the principle of synchronized

2 Detailed Explanation of AQS Locking and Unlocking Process:
Detailed Explanation of AQS Locking and Unlocking Process

The principle of synchronized, let me talk about the underlying implementation. At the beginning, I also talked about the lock upgrade process and the mutex lock in a standard way. In the end, the interviewer asked more deeply, and asked me what was in the moniter. I just remembered waitsets, entrylist, owner, and count.

Synchronized is a keyword in Java that is used to control exclusive access to an object. In a multi-threaded environment, multiple threads may access the same piece of code or the same object at the same time, which may cause some concurrency problems. By using the synchronized keyword, you can ensure that only one thread can access the synchronized modified code block or method at any time.

The implementation of synchronized mainly depends on the underlying monitor (monitor) mechanism of the JVM. In Java, each object has a monitor associated with it. When a thread executes a code block or method modified by synchronized, it needs to obtain the monitor of this object before entering this code block or method.

Some of the things included in the monitor you mentioned include:

  1. Owner: Points to the thread that owns the monitor. When a thread successfully obtains the monitor, the Owner points to this thread.

  2. EntryList: Contains all threads that request to obtain monitor but have not been successfully obtained. When a thread tries to acquire a monitor already owned by other threads, the thread will be put into the EntryList and enter the blocked state.

  3. WaitSet: Contains all threads that have executed the Object.wait() method and are waiting to be awakened. When a thread executes the Object.wait() method, it will release the monitor and enter the WaitSet, waiting for other threads to call Object.notify() or Object.notifyAll() method to wake it up.

  4. Recursion count: After a thread obtains the monitor, it can re-enter the code block or method modified by synchronized multiple times, and the recursion count is used to record the number of times the thread re-enters the monitor.

When a thread finishes executing the synchronized code block or method, it will release the monitor, and then the JVM will select a thread from the EntryList, and transfer the ownership of the monitor to this thread. In this way, this thread can enter the synchronized code block or method and start executing.

It should be noted that synchronized in Java is reentrant, that is, a thread can acquire the same monitor multiple times. This is achieved through the recursion count. Every time you re-enter, the recursion count will increase by 1, and every time you exit, the recursion count will decrease by 1. When the recursion count is 0, the thread will actually release the monitor.

The synchronized monitor object is more like relying on the underlying mutex lock of the operating system, but AQS is more like implementing a locking mechanism at the application layer level, right?

Your understanding is basically correct. But it needs to be clear that synchronizedthe keywords in Java and the interfaces java.util.concurrent.locksin the package Lock(including its implementation classes, such as ReentrantLock) are all based on the Java level, and have corresponding implementations in the JVM.

synchronizedThe implementation, especially in the early versions of the JVM, does rely on the underlying mutex lock of the operating system, which is often called a "heavyweight lock". However, in subsequent versions of the JVM (such as 1.6+), in order to improve performance, optimization techniques such as lock bias, lightweight locks, and spin locks are introduced to avoid thread blocking at the operating system level as much as possible.

AbstractQueuedSynchronizer (AQS) is a framework for building locks and synchronization components implemented at the Java application level, such as ReentrantLock, Semaphore, CountDownLatch, FutureTasketc. are all implemented based on AQS. AQS internally maintains waiting threads through a doubly linked list (Condition Queue) and a FIFO queue (Sync Queue). Therefore, AQS provides a more advanced and flexible synchronization mechanism, and compared to direct use synchronized, it provides more control options (such as interruptible fetches, fair and unfair modes, timeout fetches, etc.).

To sum up, we can think that synchronizedit is the basic implementation of JVM for concurrency control, and the AQS-based locking mechanism (such as ReentrantLock) provides a richer and more flexible synchronization control method. The two need to be selected according to specific concurrency scenarios and requirements in specific use.

For the monitor object, EntryList is equivalent to the ready queue, which stores all the threads that are awakened but have not acquired the lock, and WaitSet is equivalent to the waiting queue, waiting for the completion of the I/O operation, right?

Regarding the monitor object in Java, your understanding is basically correct. In the monitor object, EntryList is a queue that stores threads that try to acquire the monitor lock but fail. When the monitor lock is released, these threads will be woken up and try to acquire the lock again. WaitSet is a collection of threads that call the Object.wait() method and enter the blocked state. These threads wait for other threads to call the notify() or notifyAll() method of the corresponding object, which usually involves waiting for a certain condition ( rather than just waiting for I/O operations to be satisfied.

In AQS, there are actually two queues, one is the queue waiting to acquire the synchronization state (lock) (that is, Sync

Why is there only one doubly linked list in AQS and no waiting queue?

In AQS, there are actually two queues, one is the queue (that is, Sync Queue) waiting to acquire the synchronization state (lock), and the other is the waiting queue for Condition objects (that is, Condition Queue). The usage scenarios of the two queues are different: Sync Queue is mainly used to implement the lock mechanism (for example, used in ReentrantLock), and Condition Queue is mainly used to implement condition variables (for example, used in Condition). AQS is responsible for maintaining the Sync Queue, and the Condition object is responsible for maintaining the Condition Queue. The Condition object is used in AQS to support a lock with multiple waiting queues (Condition Queue), and each Condition Queue corresponds to a specific condition.

AQS uses a doubly linked list to maintain Sync Queue, and each node (Node) represents a thread waiting to acquire a lock. Each node has a status field, which is used to store the waiting status of the current thread. At the same time, Node also contains references to predecessor and successor nodes for fast traversal of the queue. When the lock is released, the thread at the head of the queue will be woken up, and when the lock acquisition fails, the thread will be inserted at the tail of the queue. In this way, the fairness of FIFO (First In First Out) can be guaranteed.

Can Condition Queue and Sync Queue in AQS be used at the same time?

Yes, Condition Queuethe sum in AQS (AbstractQueuedSynchronizer) Sync Queuecan be used at the same time. In fact, these two queues need to be used at the same time in some cases.

As ReentrantLockan example, when a thread fails to acquire a lock, it will be put into Sync Queuewait; when a thread needs to wait for a certain condition to be established when the lock has been acquired, it can call Condition.await()a method to put itself Condition Queueinto wait.

Then, when other threads release the lock, AQS will wake up Sync Queuea thread in it; when other threads call the Condition.signal()method, a thread waiting in it will be selected Condition Queueand moved to it Sync Queueso that it can be woken up when the lock is available.

So, in AQS, Condition Queueand Sync Queuecan be used at the same time, and they jointly participate in the process of thread waiting and waking up.

Must Condition Queue and Sync Queue in AQS be used at the same time?

Condition Queue and Sync Queue in AQS do not need to be used at the same time. Their use depends on how the specific synchronization component utilizes the AQS framework.

Is there any scenario where these two queues are used separately?

The two queues can be used separately. For example, synchronization components such as ReentrantLock or Semaphore mainly use Sync Queue. When threads cannot acquire locks or licenses immediately, they put threads into Sync Queue for queuing. On the other hand, when we use Condition objects (usually combined with ReentrantLock) for inter-thread communication, Condition Queue is used. When a thread calls the await() method of Condition, it will be put into Condition Queue.

For AQS, if a thread fails to acquire a lock at the beginning, which queue will it enter first?

If a thread fails to acquire the lock initially, it will first enter the Sync Queue. Sync Queue is a queue used in AQS to manage threads waiting to acquire locks. Only when the thread has acquired the lock but needs to wait for a certain condition to be met, the Condition object will be used to put the thread into the Condition Queue.

The difference between Lock and synchronized

Guess you like

Origin blog.csdn.net/yxg520s/article/details/131819176