In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-15 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
Editor to share with you Java concurrent AbstractQueuedSynchronizer source code example analysis, I believe that most people do not know much about it, so share this article for your reference, I hope you will learn a lot after reading this article, let's go to know it!
To learn Java concurrent programming, we have to understand the java.util.concurrent package, under which there are many concurrency utility classes that we often use, such as ReentrantLock, CountDownLatch, CyclicBarrier, Semaphore and so on. The underlying implementation of these classes depends on the AbstractQueuedSynchronizer class, which shows the importance of this class. So in the Java concurrency series of articles, I first analyze the AbstractQueuedSynchronizer class, because this class is more important, and the code is relatively long, in order to analyze as thoroughly as possible, I decided to use four articles to give a more complete introduction to this class. The main purpose of this article as an overview is to give readers a preliminary understanding of this class. For simplicity, AQS will be used to represent this class in some subsequent places.
1. What is the AbstractQueuedSynchronizer class for?
It is believed that many readers have used ReentrantLock, but are not aware of the existence of AbstractQueuedSynchronizer. In fact, ReentrantLock implements an inner class Sync, which inherits AbstractQueuedSynchronizer. The implementation of all locking mechanisms depends on the inner class of Sync. It can also be said that the implementation of ReentrantLock depends on the AbstractQueuedSynchronizer class. Similarly, classes such as CountDownLatch, CyclicBarrier, and Semaphore implement their own control of locks in the same way. You can see that AbstractQueuedSynchronizer is the cornerstone of these classes. So what exactly is implemented within AQS so that these classes depend on it? It can be said that AQS provides the infrastructure for these classes, that is, a password lock, and these classes can set the password of the password lock themselves after they have the password lock. In addition, AQS also provides a queuing area and a thread trainer, and we know that a thread is like a primitive barbarian, it has no manners, it will only go on a rampage, so you have to teach it step by step, tell it when to queue, where to queue, what to do before the queue, what to do after the queue. All this enlightenment work has been done by AQS, and the threads taught from it have become very civilized and polite, and are no longer primitive barbarians, so we only need to deal with these civilized threads in the future. Do not have too much contact with the original thread!
two。 Why does AbstractQueuedSynchronizer provide a password lock?
/ / the head node of the synchronization queue private transient volatile Node head; / / the tail node of the synchronization queue private transient volatile Node tail;// synchronization status private volatile int state;// gets the synchronization status protected final int getState () {return state;} / / sets the synchronization status protected final void setState (int newState) {state = newState;} / / sets the synchronization status protected final boolean compareAndSetState (int expect, int update) {return unsafe.compareAndSwapInt (this, stateOffset, expect, update);}
The above code lists all the member variables of AQS, and you can see that there are only three member variables of AQS, namely, synchronous queue header node reference, synchronization queue tail node reference, and synchronization status. Note that all three member variables are modified with the volatile keyword, which ensures that changes made to it by multiple threads are visible in memory. The core of the whole class is the synchronization state. You can see that the synchronization state is actually an int variable. You can think of the synchronization state as a password lock and a password lock locked from the room. The specific value of state is equivalent to the password controlling the opening and closing of the password lock. Of course, the password of the lock is determined by each subclass. For example, in ReentrantLock, state equals 0 means the lock is open, state greater than 0 means the lock is locked, while in Semaphore, state greater than 0 means the lock is open, and state equals 0 means the lock is locked.
3. How is the queue area of AbstractQueuedSynchronizer implemented?
There are actually two queuing areas inside the AbstractQueuedSynchronizer, one is the synchronization queue and the other is the conditional queue. As you can see from the figure above, there is only one synchronization queue, while there can be multiple conditional queues. The node of the synchronization queue holds the reference of the front and back node respectively, while the node of the conditional queue has only one reference to the successor node. T in the figure represents a thread, each node contains a thread, the thread first enters the synchronous queue after the failure to acquire the lock, and the thread must hold the lock in order to enter the conditional queue. Next, let's look at the structure of each node in the queue.
/ / the node of the synchronization queue static final class Node {static final Node SHARED = new Node (); / / indicates that the current thread holds the lock in shared mode static final Node EXCLUSIVE = null; / / indicates that the current thread holds the lock in exclusive mode static final int CANCELLED = 1; / / indicates that the current node has canceled the acquisition of lock static final int SIGNAL =-1; / / indicates that the thread of the successor node needs to run static final int CONDITION =-2 / / indicates that the current node is queued in the conditional queue static final int PROPAGATE =-3; / / indicates that the successor node can directly acquire the lock volatile int waitStatus; / / indicates the waiting status of the current node volatile Node prev; / / indicates that the previous successor node volatile Node next; / / represents the thread reference Node nextWaiter held by the successor node volatile Thread thread; / / in the synchronization queue / / indicates whether the successor node in the conditional queue / / whether the current node state is the shared mode final boolean isShared () {return nextWaiter = = SHARED;} / / returns the previous node final Node predecessor () throws NullPointerException {Node p = prev; if (p = = null) {throw new NullPointerException ();} else {return p }} / / Constructor 1 Node () {} / / Constructor 2, which is used by default with this constructor Node (Thread thread, Node mode) {/ / Note that the holding mode is assigned to nextWaiter this.nextWaiter = mode; this.thread = thread;} / / constructor 3, and only Node (Thread thread, int waitStatus) {this.waitStatus = waitStatus; this.thread = thread;}} is used in the conditional queue.
Node represents a node in the synchronization queue and the conditional queue, which is the inner class of AbstractQueuedSynchronizer. Node has many properties, such as hold mode, wait status, successors and successors in synchronization queues, subsequent references in conditional queues, and so on. The synchronization queue and the conditional queue can be regarded as the queuing area, each node as the seat of the queuing area, and the thread as the queuing guest. When guests first arrive, they will knock on the door to see if the lock is open. if the lock is not opened, they will go to the queuing area to get a number plate, declare how they want to hold the lock, and finally queue at the end of the queue.
4 how to understand the exclusive mode and the shared mode?
As mentioned earlier, each guest will get a number plate before queuing and declare how he or she wants to possess the lock. The way of owning the lock can be divided into exclusive mode and shared mode, so how to understand the exclusive mode and shared mode? Really can not find any good metaphor, we can think of the public toilet, exclusive mode of people are more domineering, I either do not enter, no one else is allowed to enter, alone to occupy the whole toilet. People in shared mode are not so fastidious. When it finds that the toilet is ready for use, it doesn't count if it comes in by itself, and it has to enthusiastically ask the people behind if they mind using it together. If the people behind don't mind using it together, then they don't have to queue up together. Of course, if the people behind mind, they have to stay in the queue and continue to queue up.
5 how to understand the waiting state of nodes?
We also see that each node has a wait state, which is divided into four CANCELLED,SIGNAL,CONDITION,PROPAGATE states. Think of this waiting state as a sign hanging next to the seat, indicating the waiting status of the person in the current seat. The status of this brand can be modified not only by itself, but also by others. For example, when the thread is ready to give up while queuing, it will set the sign on its seat to CANCELLED so that others can see it and clean it out of the queue. In another case, when the thread is about to fall asleep in the seat, it is afraid that it will oversleep, so it will change the sign on the front position to SIGNAL, because everyone will go back to their seat before leaving the queue, and if they see the sign with the status of SIGNAL, it will wake up the next person. Only by making sure that the brand in the front position is SIGNAL, the current thread will sleep peacefully. The CONDITION status indicates that the thread is queued in the conditional queue, and the PROPAGATE status reminds later threads that they can acquire the lock directly. This state is only used in shared mode, which will be discussed later when we talk about shared mode separately.
6. What does a node do when it enters the synchronization queue?
/ / Node queue operation, return the previous node private Node enq (final Node node) {for (;;) {/ / get synchronization queue tail node reference Node t = tail; / / if the end node is empty, the synchronization queue has not been initialized if (t = = null) {/ / initialize the synchronization queue if (compareAndSetHead (new Node () {tail = head;}} else {/ / 1. Point to the current tail node node.prev = t; / / 2. Set the current node to the tail node if (compareAndSetTail (t, node)) {/ / 3. Point the successor of the old tail node to the new tail node t.next = node; / / for loop unique exit return t;}
Note that the queuing operation uses an endless loop, which is returned only if the node is successfully added to the end of the synchronization queue, and the result is the original tail node of the synchronization queue. The following figure illustrates the whole operation.
Readers need to pay attention to the order of adding tail nodes, which is divided into three steps: pointing to the tail node, CAS changing the tail node, and pointing the successor of the old tail node to the current node. In a concurrent environment, these three steps may not be guaranteed to be completed, so in the operation of emptying all canceled nodes in the synchronization queue, in order to find nodes in a non-canceled state, they are traversed not from front to back but from back to forward. In addition, when each node enters the queue, its wait state is 0, and the wait state of the previous node will be changed to SIGNAL only when the thread of the successor node needs to be suspended.
Note: all the above analysis is based on JDK1.7, there will be differences between different versions, readers should pay attention to.
The above is all the content of this article "sample Analysis of AbstractQueuedSynchronizer Source Code of Java concurrency". Thank you for reading! I believe we all have a certain understanding, hope to share the content to help you, if you want to learn more knowledge, welcome to follow the industry information channel!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.