Java concurrency Series [1]----abstractqueuedsynchronizer analysis of source code analysis

Source: Internet
Author: User
Tags cas prev semaphore volatile

Learn Java concurrency programming have to understand java.util.concurrent this package, this package has many of the concurrency tools we often use, such as: Reentrantlock, Countdownlatch, Cyclicbarrier, Semaphore and so on. The underlying implementations of these classes depend on the Abstractqueuedsynchronizer class, which shows the importance of this class. So in the Java Concurrency Series I first abstractqueuedsynchronizer this class to analyze, because this class is more important, and the code is relatively long, in order to be as thorough as possible analysis, I decided to use four articles to a more complete description of the class. This article as a summary of the main is to let readers have a preliminary understanding of the class. For the sake of simplicity, there are some places where Aqs represent this class.

1. What does the Abstractqueuedsynchronizer class do?

It is believed that many readers have used reentrantlock, but they do not know the existence of Abstractqueuedsynchronizer. In fact, Reentrantlock implements an internal class sync, which inherits the Abstractqueuedsynchronizer, and all of the lock mechanism implementations are dependent on the sync internal class, It can also be said that the implementation of Reentrantlock is dependent on the Abstractqueuedsynchronizer class. Similarly, Countdownlatch, Cyclicbarrier, semaphore These classes also implement their own lock control in the same way. As can be seen, Abstractqueuedsynchronizer is the cornerstone of these classes. So what does AQS internally achieve so that all these classes depend on it? As you can say, AQS provides the infrastructure for these classes, which provides a password lock that can be used to set the password lock password after the password lock. In addition, AQS provides a queue area, and provides a thread trainer, we know the thread is like a primitive savage, it does not know how to be polite, it will only go on the rampage, so you have to teach it step-by-step, tell it when to line up, where to go to line up, what to do before the queue, What to do when you are in line. All these civilized work by Aqs to help you to complete, from it here the thread of the Enlightenment is very civilized and polite, no longer the primitive barbarian, so we only need to deal with these civilized threads on the line, do not have too much contact with the original thread!

2. Why does Abstractqueuedsynchronizer provide a password lock?

1 //the head node of the synchronization queue2 Private transient volatileNode head;3 4 //tail node of the synchronization queue5 Private transient volatileNode tail;6 7 //Synchronization Status8 Private volatile intState ;9 Ten //Get synchronization Status One protected Final intgetState () { A     returnState ; - } -  the //Set synchronization Status - protected Final voidSetState (intnewstate) { -State =newstate; - } +  - //set the synchronization state in CAS mode + protected Final BooleanCompareandsetstate (intExpectintupdate) { A     returnUnsafe.compareandswapint ( This, Stateoffset, expect, update); at}

The above code lists all the member variables of the AQS, and you can see that there are only three member variables for the AQS, namely the synchronous Queue Header node reference, the synchronization queue tail node reference, and the synchronization status. Note that these three member variables are decorated with the volatile keyword, which ensures that the changes made to it by multiple threads are memory-visible. The core of the whole class is this synchronization state, you can see the synchronization state is actually an int type of variable, we can take this synchronization state as a password lock, but also from the room lock up the password lock, the state specific value is equivalent to the password control password lock opening and closing. Of course, the password of this lock is defined by each sub-class, for example, in Reentrantlock, state equals 0 means that the lock is open, state is greater than 0 means the lock is locked, and in Semaphore, the state is greater than 0 means that the lock is open, State equals 0 means the lock is locked.

2. How does the Abstractqueuedsynchronizer queue area be implemented?

Abstractqueuedsynchronizer There are actually two queued areas, one is the synchronization queue, and one is the conditional queue. As you can see, there is only one synchronization queue, and the conditional queue can have multiple. The nodes of the synchronization queue hold references to the front and back nodes, and the nodes of the conditional queue have only one reference to the successor node. In the figure, T represents a thread, each node contains a thread, and the thread first enters the synchronization queue after the lock failure, and the thread that wants to enter the conditional queue must hold the lock. Next we look at the structure of each node in the queue.

1 //node of the synchronization queue2 Static Final classNode {3     4     Static FinalNode SHARED =NewNode ();//indicates that the current thread holds the lock in shared mode5     6     Static FinalNode EXCLUSIVE =NULL;//indicates that the current thread holds the lock in exclusive mode7 8     Static Final intCANCELLED = 1;//indicates that the current node has been canceled to acquire the lock.9     Ten     Static Final intSIGNAL =-1;//the thread that represents the successor node needs to run One      A     Static Final intCONDITION =-2;//indicates that the current node is queued in the condition queue -      -     Static Final intPROPAGATE =-3;//indicates that the subsequent node can acquire the lock directly. the  -     volatile intWaitstatus;//indicates the wait state of the current node. -     -     volatileNode prev;//represents a forward node in a synchronization queue +  -     volatileNode Next;//represents the successor node in the synchronization queue +  A     volatileThread thread;//current node-held thread reference at      -Node Nextwaiter;//represents the successor node in the conditional queue -  -     //whether the current node state is a shared mode -     Final BooleanisShared () { -         returnNextwaiter = =Gkfx; in     } -  to     //returns the forward node of the current node . +     FinalNode predecessor ()throwsNullPointerException { -Node p =prev; the         if(p = =NULL) { *             Throw Newnullpointerexception (); $}Else {Panax Notoginseng             returnp; -         } the     } +      A     //Constructor 1 the Node () {} +      -     //Constructor 2, which is used by default with this constructor $ node (thread thread, node mode) { $         //Note that the hold mode is assigned to Nextwaiter -          This. Nextwaiter =mode; -          This. Thread =thread; the     } -     Wuyi     //Constructor 3, used only in the conditional queue theNode (thread thread,intwaitstatus) { -          This. Waitstatus =Waitstatus; Wu          This. Thread =thread; -     } About}

Node represents a node in the synchronization queue and the conditional queue, which is the inner class of the Abstractqueuedsynchronizer. Node has a number of attributes, such as hold mode, wait state, pre-and successor in the synchronization queue, and subsequent references in the conditional queue, and so on. You can think of the synchronization queue and the conditional queue as a queue area, each node as a seat in a queued area, and a thread as a queued guest. When guests first come, they will knock on the door to see if the lock is open, and if the lock does not open it will go to the queue area to pick up a number card, declare how you want to hold the lock, and then queue at the end of the line.

3. How to understand exclusive mode and sharing mode?

In front of each guest in the queue will receive a number card, declaring how they want to occupy the lock, the way to occupy the lock is divided into exclusive mode and sharing mode, then how to understand the exclusive mode and sharing mode? Really can't find any good metaphor, we can think of public toilets, the monopoly mode of people more overbearing, I either do not enter, come in and no one else into the, oneself alone occupy the entire toilet. Sharing mode of the person is not so fastidious, when it found that the toilet has been ready to use, it does not count itself, but also enthusiastic to ask the people behind the next if you do not mind to use together, if the people do not mind using together that will not have to queue up together on it, Of course, if the people in the back mind, then they have to stay in the queue and continue to line up.

4. How to understand the waiting state of the node?

We also see that each node has a waiting state, which is divided into four states of cancelled,signal,condition,propagate. This wait state can be thought of as the sign that hangs next to the seat, identifying the waiting state of the person on 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 in the queue, it will set the sign on its seat to cancelled so that others can see it and clear it out of the queue. Another situation is that when the thread is in the seat to fall asleep, it is afraid to sleep over the head, will be in front of the position of the brand to signal, because everyone in the queue before leaving will return to their own seat to take a look, if you see the sign on the status of Signal, it will go to wake up the next person. Only make sure the front position of the brand is signal, the current thread will be relieved to sleep. The condition state indicates that the thread is queued in the conditional queue, and the thread behind the propagate status alert can get the lock directly, as it will be when shared mode is used, and then shared mode is discussed separately.

5. What happens when a node enters the sync queue?

1 //the node is queued and returned to the previous node .2 PrivateNode Enq (Finalnode node) {3      for (;;) {4         //get the synchronization queue tail node reference5Node T =tail;6         //If the tail node is empty, the synchronization queue has not been initialized.7         if(T = =NULL) {8             //initializing the synchronization queue9             if(Compareandsethead (NewNode ())) {TenTail =head; One             } A}Else { -             //1. Point to the current tail node -Node.prev =T; the             //2. Set the current node as 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 only exit -                 returnT; +             } A         } at     } -}

Note that the queued operation uses a dead loop, and only the successful addition of the node to the end of the synchronization queue is returned, and the result is the original tail node of the synchronization queue. Demonstrates the entire operation process.

Readers need to be aware of the order in which the tail nodes are added, divided into three steps: point to the tail node, CAS change the tail node, and point the successor of the old tail node to the current node. In a concurrency environment, these three steps do not necessarily guarantee completion, so in order to clear all the canceled nodes of the synchronization queue, to find a node that is not in the cancellation state, it does not traverse backwards but from backward forward. Also, each node enters the queue when its wait state is 0, and the wait state of the previous node is changed to signal only if 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 need to pay attention to

Java concurrency Series [1]----abstractqueuedsynchronizer analysis of source code analysis

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.