In-depth multithreading--reentrantlock (a) The basic use of this class is introduced, and the lock () and Unlock () methods are analyzed in the view of source code. On this basis, I would like to introduce another extremely important method Newcondition (), in fact, this category is not part of the Reentrantlock category, is an implementation of the Java.util.concurrent.locks.Condition interface, located in the inner class Conditionobject in Abstractqueuedsynchronizer (abbreviation: AQS).
This class provides methods such as await* (), signal* (), and so on. This time only the await (), signal () method in the source of the angle to parse.
Principle analysis await () method analysis Conditionobject.await ()
1 Public Final voidAwait ()throwsinterruptedexception {2 if(thread.interrupted ())3 Throw Newinterruptedexception ();4Node node =Addconditionwaiter ();5 intsavedstate =fullyrelease (node);6 intInterruptmode = 0;7 while(!isonsyncqueue (node)) {8Locksupport.park ( This);9 if((Interruptmode = checkinterruptwhilewaiting (node))! = 0)Ten Break; One } A if(Acquirequeued (node, savedstate) && interruptmode! =Throw_ie) -Interruptmode =Reinterrupt; - if(Node.nextwaiter! =NULL)//Clean up if cancelled the unlinkcancelledwaiters (); - if(Interruptmode! = 0) - reportinterruptafterwait (interruptmode); -}
1, determine whether the thread is interrupted, if interrupted, throw interruptedexception.
2. Call the Addconditionwaiter () method to add the current thread to the wait queue.
3, line 5th, call the Fullyrelease (Node) method, try to free the current thread and return the state value before the release.
4, Line 7th, while the loop condition is Isonsyncqueue (Node) inversion, that is, the method must return False to enter the loop body. After entering, call Locksupport.park () to suspend the current thread.
5. Wait for the signal () method to be called and join the synchronization queue to wait for dispatch. After dispatch, the thread goes down because it is already in the synchronization queue and the while loop jumps out.
6. Come to line 12th, try to restore the value of state to await, and if the restore succeeds, the thread continues to go down. If the period is not successfully stated and is already occupied by another thread, continue to wait.
7. If the currently waiting node has a downstream waiting node, the waiting node is canceled while the cleanup is in progress.
8. After execution of the method executes, the thread's business continues until it is called to unlock ().
Conditionobject.addconditionwaiter ()
1 PrivateNode Addconditionwaiter () {2Node T =Lastwaiter;3 //If Lastwaiter is cancelled.4 if(t! =NULL&& T.waitstatus! =node.condition) {5 unlinkcancelledwaiters ();6t =Lastwaiter;7 }8Node node =NewNode (Thread.CurrentThread (), node.condition);9 if(T = =NULL)TenFirstwaiter =node; One Else AT.nextwaiter =node; -Lastwaiter =node; - returnnode; the}
1, to determine whether Lastwaiter is a valid state, if invalid, execute the Unlinkcancelledwaiters () method, the invalid node is cleared away. Sets the current thread to a node,waitstatus value of-2.
2. Determine if Lastwaiter is null, and if NULL is empty, the created node is assigned to the Firstwaiter property of the queue, and if not NULL, the downstream of the last node of the queue (because the await () method is called for the first time , Lastwaiter must be empty at this time). Then set the Lastwaiter property of the queue to the new node.
Condition.fullyrelease (Node)
Final intFullyrelease (node node) {BooleanFailed =true; Try { intsavedstate =getState (); if(Release (savedstate)) {failed=false; returnsavedstate; } Else { Throw Newillegalmonitorstateexception (); } } finally { if(failed) Node.waitstatus=node.cancelled; } }
1. Gets the state value of the current thread, and then calls Aqs.release (int) to attempt to free the current thread, returning the thread state if the release succeeds.
An analysis of the aqs.relase (int) method has been described in detail in the previous article. To view please click
2. If there is no successful release, the exception illegalmonitorstateexception is thrown and the Node.waitstatus state is set to cancel.
Abstractqueuedsynchronizer.isonsyncqueue (Node)
1 Final BooleanIsonsyncqueue (node node) {2 if(Node.waitstatus = = Node.condition | | node.prev = =NULL)3 return false;4 if(Node.next! =NULL)//If has successor, it must is on queue5 return true;6 7 returnfindnodefromtail (node);8}
This method literally means whether the current node is in a synchronous queue, and if so, returns True. This place is very difficult to understand, I try to explain it in an easy-to-understand way.
1, the 2nd line, determine whether the current node's Waitstatus value is -2 (await ()) or whether Node.prev is null, both satisfy their first return false. Determine if the value of node's waitstatus is-2 very good understanding, called after the await, the first time to come to this method, is certainly set up. Determine if Node.prev is null, this place is a parity, the first time in the same null. When is this condition not tenable? At that time to see a little dizzy, so open associative mode, finally have a point of thinking, that is, call the await () method thread must be in the synchronization queue head, at this time his prev must be null, after seeing the signal () method, You will need to rejoin the synchronization queue when you see that the thread is woken. At this point only at the end of the queue, Node.prev is directed to his upstream node.
2, when the first judgment is all not true, then the second judgment is executed, whether the node.next is null or NOT NULL returns TRUE. This place is where he is already in the sync queue and already has a downstream node.
3, the first two judgments are not satisfied with the case directly called Findnodefromtail (node), the literal meaning is to find node from the end of the queue, under what circumstances will be called to this method? Node itself is called at the end.
Signal () method Analysis Conditionobject.signal ()
1 Public Final voidsignal () {2 if(!isheldexclusively ())3 Throw Newillegalmonitorstateexception ();4Node first =Firstwaiter;5 if(First! =NULL)6 dosignal (first);7}
Gets the first waiting person, if not null, to execute dosignal (Node)
Conditionobject.dosignal (Node)
1 Private voiddosignal (Node first) {2 Do {3 if((Firstwaiter = first.nextwaiter) = =NULL)4Lastwaiter =NULL;5First.nextwaiter =NULL;6} while(!transferforsignal (first) &&7(first = firstwaiter)! =NULL);8}
1. Enter the Do-while loop body to determine if the first.nextwaiter is null, or NULL to set the Lastwaiter to null.
2. Immediately after entering the while condition, the condition of the continuation loop returns false for Call Transferforsignal (Node), and firstwaiter is not null.
Abstractqueuedsynchronizer.transferforsignal (Node)
1 Final Booleantransferforsignal (node node) {2 3 if(!compareandsetwaitstatus (node, node.condition, 0))4 return false;5 6Node p =Enq (node);7 intWS =P.waitstatus;8 if(ws > 0 | |!)compareandsetwaitstatus (P, WS, node.signal))9 Locksupport.unpark (node.thread);Ten return true; One}
1, first set the current node's Waitstatus value from 2 to 0, and determine whether to return false. If False is returned, the thread is canceled.
2. Call the familiar Enq (node) method to stitch the current node into the synchronization queue and return to node upstream nodes p.
3, at this time P waitstatus equals 0. So go directly to the second judging condition and set P's waitstatus from 0 to-1. If this setting fails, the current node will be unlocked directly. Set the premise of failure the personal understanding is that P is running, that is, Locksupport.unpark (P.thread) is called, and there is a case where the thread is canceled.
Summarize
1, condition provides a set of thread wait and wake mechanism, and match it to object.wait/notify methods. However, the latter condition is synchronized and cannot be applied directly in Reentrantlock.
2, condition can exist in a lock object multiple, flexible and convenient.
3, Conditionobject class also has a large number of AQS operations, also shows that AQS is the basic framework of the synchronization framework.
In-depth multithreading--reentrantlock (ii)