Java Concurrency Programming-reentrantlock

Source: Internet
Author: User
Tags cas

The above has summed up the past life of Aqs, with this foundation we can further learn the concurrency tool class. The first thing we want to learn is Reentrantlock, this article will be from the background of Reentrantlock, source code principle and application to learn reentrantlock this concurrency tool class.

1. Create a background

We have already learned synchronized, the key word to ensure that the object in the concurrent access to the atomicity, visibility and ordering, the bottom of the keyword to be implemented by the JVM through C + +, since it is the JVM implementation, depends on the JVM, Programmers will not be able to scale and optimize at the Java level, the flexibility is certainly not high, such as the use of programmers can not interrupt a waiting to acquire a lock thread, or can not request a lock infinite wait. Based on this background, Doug Lea Constructs a Java class that has the same effect as synchronized in memory semantics, while also extending some other advanced features, such as timed lock waits, interruptible lock waits, and fairness, which is reentrantlock.

2. Source Code Principle Analysis

2.1 Principle of Re-entry

In the synchronized article, we think that synchronized is a heavyweight lock, its implementation corresponds to the C + + Objectmonitor, the code is as follows:

Objectmonitor () {_header=NULL; _count=0;//record the number of times a thread acquires a lock_waiters =0; _recursions=0;//number of times the lock was re-entered_object =NULL; _owner= NULL;//point to the thread holding the Objectmonitor object_waitset = NULL;//wait condition queue similar to Aqs conditionobject_waitsetlock =0 ; _responsible=NULL; _SUCC=NULL; _CXQ=NULL; Freenext=NULL; _entrylist= NULL;//synchronization queue CLH queue similar to Aqs_spinfreq =0 ; _spinclock=0 ; Owneristhread=0 ; _previous_owner_tid=0; }

From the code, you can see that the synchronized implementation of the lock is dependent on JVM,JVM for each object's lock associated with a counter _count and an owner thread _owner, when the counter is 0, it is assumed that the lock is not held by any thread, when the thread requests a lock that is not held, The JVM notes the holder of the lock and sets the value of the counter to 1, and if the same thread acquires the lock again, the value of the counter increments, and when the thread exits, the value of the counter decrements until the counter is 0 o'clock, and the lock is released.

Reentrantlock realized in memory semantics synchronized, is also support reentrant, then Reentrantlock is how to support it, let us look at the implementation of the non-fair lock reentrantlock Reentrant, the code is as follows:

Final BooleanNonfairtryacquire (intacquires) {            FinalThread current = Thread.CurrentThread ();//Current Thread            intc =getState (); if(c = = 0) {//indicates that the lock has not been preempted                if(Compareandsetstate (0, acquires)) {//get to synchronization statusSetexclusiveownerthread (current);//Current thread Possession lock                    return true; }            }            Else if(Current = = Getexclusiveownerthread ()) {//the thread has taken possession of the lock and re-entered                intNEXTC = c + acquires;//number of times the synchronization state record was re-entered                if(NEXTC < 0)//Overflow                    Throw NewError ("Maximum Lock count Exceeded");                SetState (NEXTC); return true; }            return false; }        protected Final BooleanTryrelease (intreleases) {            intc = getState ()-releases;//since reentrant, you need to release the lock that is acquired by re-entry.            if(Thread.CurrentThread ()! =Getexclusiveownerthread ())Throw Newillegalmonitorstateexception (); BooleanFree =false; if(c = = 0) { free=true;//returns true only if the thread is all releasedSetexclusiveownerthread (NULL);//the thread that synchronizes the queue can go to get the synchronization state.} setState (c); returnFree ; }

See this also understand the above mentioned Reentrantlock class uses the Aqs synchronization state to hold the number of times the lock is held repeatedly. When a lock is fetched by a thread, Reentrantlock also records the thread identity that is currently acquiring the lock, to check for duplicates, and to detect the presence of an illegal state exception when the wrong thread attempts to unlock the operation.

2.2 Acquiring and releasing locks

Here's how to get and release locks:

 Public void Lock () {   sync.lock (); // Get lock }publicvoid  unlock () {   sync.release (// release lock }

The lock is dependent on the internal class Sync lock () method, the method has 2 implementation class methods, respectively, is the unfair lock Nonfairsync and fair lock Fairsync, the next section of the analysis. Then look at the release lock, release the lock when the actual call is Aqs's release method, the code is as follows:

 Public Final BooleanReleaseintArg) {        if(Tryrelease (ARG)) {//calling a subclass of Tryrelease is actually the tryrelease of syncNode h = head;//take the head node of the synchronization queue            if(H! =NULL&& H.waitstatus! = 0)//Synchronization Queue Header node is not empty and is not an initial stateUnparksuccessor (h);//releasing the head node wakes subsequent nodes            return true; }        return false;}

Sync's tryrelease is the last section of the re-entry method, if it is the same thread, then the number of re-entry of the lock is decremented, until the number of re-entry is 0, this method will return true, at this time the end of the node wakes up the subsequent node to get the synchronization state of Aqs.

2.3 Fair lock and non-fair lock

The fair lock or the unfair lock depends on the construction method of the Reentrantlock, the default parameterless construction method is Nonfairsync, with the parameter construction method, the entry parameter is True Fairsync, the entry parameter is false to Nonfairsync.

 Public Reentrantlock () {   new  Nonfairsync ();}  Public Reentrantlock (boolean  Fair) {   newnew  Nonfairsync ();}

Let's look at the implementation of the unfair lock and the fair lock separately.

Static Final classNonfairsyncextendsSync {Private Static Final LongSerialversionuid = 7316153563782823691L; /*** performs lock.         Try immediate barge, backing up to normal * acquire on failure. */        Final voidLock () {if(Compareandsetstate (0, 1))//to get the sync state via CAs is the lockSetexclusiveownerthread (Thread.CurrentThread ());//get successful thread possession lock            ElseAcquire (1);//gets the acquire method that failed to enter the Aqs synchronization queue queued for execution Aqs        }        protected Final BooleanTryacquire (intacquires) {            returnNonfairtryacquire (acquires); }    }

In Aqs's Acquire method, the subclass Tryacquire is called First, which is Nonfairtryacquire, see section 2.1. Can be seen in the non-fair lock, Rob Aqs synchronization state is not necessarily the first node of the synchronization queue, as long as the thread through the CAs to seize the synchronization state or acquire in the synchronization state, the priority to occupy the lock, and relative synchronization queue this strict FIFO queue, so it will be considered to be non-fair lock.

Static Final classFairsyncextendsSync {Private Static Final LongSerialversionuid = -3000897897090466540l; Final voidLock () {Acquire (1);//strictly follow the Aqs synchronization queue requirements to get the synchronization status        }        /*** Fair version of Tryacquire.         Don ' t grant access unless * recursive call or no waiters or is first. */        protected Final BooleanTryacquire (intacquires) {            FinalThread current = Thread.CurrentThread ();//gets the current thread            intc =getState (); if(c = = 0) {//Lock not preempted                if(!hasqueuedpredecessors () &&//No precursor nodeCompareandsetstate (0, acquires)) {//cas get sync statusSetexclusiveownerthread (current); return true; }            }            Else if(Current = = Getexclusiveownerthread ()) {//The lock has been preempted and the thread is re-entered                intNEXTC = c + acquires;//synchronization status number of times                if(NEXTC < 0)                    Throw NewError ("Maximum Lock count Exceeded");                SetState (NEXTC); return true; }            return false; }    }

The implementation of the fair lock calls the Aqs acquire method directly, calling Tryacquire in acquire. Compared with the unfair lock, the CAS will not be executed once, and then when the tryacquire goes to seize the lock, it will call hasqueuedpredecessors to see if there is a node in front of it waiting to acquire the lock, and if so, the predecessor node of the synchronization queue takes precedence.

 Public Final Booleanhasqueuedpredecessors () {//The correctness of this depends on head being initialized//before tail and on Head.next being accurate if the current//Thread is the first in queue.Node t = tail;//Read fields in reverse initialization order tail nodeNode h = head;//head NodeNode S; returnH! = T &&//The kinsoku node is not a queued thread that has a queue(s = h.next) = =NULL|| S.thread! = Thread.CurrentThread ());//The subsequent node of the head node is empty or not the current thread}

Although fair lock seems to be fairer than unfair lock, but the fair lock paid a lot of thread switching cost, and not fair lock in the lock is not guaranteed fairness, there is a possibility of lock starvation, that is, some threads acquire locks several times and some threads do not get locks, there is not a lot of thread switching to ensure the non-fair lock throughput.

3. Application

3.1 Common Thread Lock

The standard form is as follows:

New Reentrantlock (); Try {        lock.lock ();      // ... }finally  {     lock.unlock ();}

This usage is the same as the synchronized effect, but the declaration of lock and unlock must be displayed.

3.2 Lock with limit

 Public boolean trylock ()//  try to get lock, return immediately get result poll lock publicboolean trylock (long Timeout, timeunit unit)// try to acquire a lock, wait for timeout time to expire lock publicvoid lockinterruptibly ()// interruptible Lock, call thread interrupt method, the lock method throws Interruptedexception  interrupt lock

You can see the reentrantlocktest in the GitHub link.

3.3 Wait/notification model

There are some flaws in the built-in queue, where each built-in lock can only correlate one conditional queue (_waitset), which causes multiple threads to wait for different conditional predicates on the same condition queue, and if each use of notify wakes up the conditional queue, it may wake the wrong thread causing the wake to fail. However, if you use Notifyall, you can wake up to the correct thread, because all threads are awakened, which also poses the problem that conditional predicates that should not be woken up and found not to wait for themselves will be suspended. Such operations can lead to wasted system resources and reduced system performance. This time, it is recommended to use explicit lock and condition instead of built-in locks and conditional queues to control the condition of multiple conditional predicates to achieve precise control of wake-up and suspend of threads. After the detailed analysis of the JVM's built-in lock, conditional queue model and the explicit lock, condition model, in fact, Aqs also mentioned in the lock, condition model.

3.4 and synchronized comparison

The difference between the two is broadly as follows:

Synchronized

Reentrantlock

Use the wait, notify, notifyall scheduling mechanism of the object itself

Thread scheduling in conjunction with condition

Explicit use in synchronous methods or synchronous code blocks

Explicit declarations specify the starting and ending positions

Managed for JVM execution, no deadlock due to exception, or not released

Manual release Lock

Prior to Jdk1.6, Reentrantlock performance was better than synchronized, but after 1.6, synchronized did a lot of performance tuning, and synchronized is relatively simple and familiar to programmers, if not synchronized features that cannot be implemented, such as Polling locks, timeout locks, interrupt locks, etc., it is recommended to use synchronized first, and then use Reentrantlock for advanced features of the lock.

Resources:

Github.com/lingjiango/concurrentprogrampractice

Www.ibm.com/developerworks/cn/java/j-jtp10264/index.html

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.