Semaphore signal Source Analysis of Java concurrent programming

Source: Internet
Author: User
Tags cas semaphore

The use and principle analysis of Semaphore in JUC, Semaphore is also a Synchronizer in Java, unlike Countdownlatch and cyclebarrier, the internal counter is incremented, so what is the internal implementation of Semaphore? It?

The Semaphore semaphore is also a synchronization container in Java, unlike Countdownlatch and Cyclicbarrier, where the counters inside it are incremented. In order to be able to list the internal structure of semaphore, we first need to look at the Semaphore class diagram, the class diagram, as follows:

such as the above class diagram can know Semaphoren internal or use AQS to achieve, sync is only a modification of AQS, and sync has two implementation classes, respectively, to get the semaphore when the fair policy is taken. When creating semaphore, there will be a variable indicating whether a fair strategy is used, the source code is as follows:

     Public Semaphore (int  permits) {        new  Nonfairsync (permits);    }      Public Semaphore (int  permits, Boolean fair) {        newnew                Nonfairsync (permits);    }   Sync (int  permits) {       setState (permits);   }

As shown in the above code, the semaphore default is a non-fairness policy, if you need a fair strategy, you can use a constructor with two parameters to construct the semaphore object, and, like Countdownlatch, the number of initialized semaphores passed within the constructor The permits is assigned to the AQS state variable, which means that the value Aqs here represents the number of semaphores currently held.

Next we mainly look at semaphore implementation of the main method of the source code, as follows:

1.void acquire () when the current thread calls the method, the goal is to obtain a semaphore resource, if the current semaphore count is greater than 0, and the current thread acquires a semaphore, the method returns directly, and the current semaphore count is reduced by 1. Otherwise it is put into the Aqs blocking queue, the current thread is suspended until the other thread calls the release method to release the semaphore, and the current thread obtains a change to the semaphore through the competition. When the current thread is called by another thread after the Interrupte () method is interrupted, the current thread throws a Interruptedexception exception to return. The source code is as follows:

    Public voidacquire () throws Interruptedexception {//Pass parameter is 1, indicating that you want to get 1 semaphore resourcesSync.acquiresharedinterruptibly (1); }    PublicFinalvoidAcquiresharedinterruptibly (intArg) throws Interruptedexception {//(1) throws an interrupt exception if the thread is interrupted        if(thread.interrupted ())Throw Newinterruptedexception (); //(2) No person calls the sync subclass method to try to get, here according to the constructor to determine the use of fair policy        if(Tryacquireshared (ARG) <0)            //If the fetch fails, put the blocking queue, and then try again if it fails, call the park method to suspend the current threaddoacquiresharedinterruptibly (ARG); }

As the above code shows, acquire () internally invokes the Acquiresharedinterruptibly method of sync, which responds to interrupts (if the current thread is interrupted, throws an interrupt exception), The method of trying to get the aqs of the semaphore resource tryacquireshared is implemented by the subclass of sync, so it is necessary to divide the fairness, here first discuss the Tryacquireshared method of the non-fair strategy Nonfairsync class, the source code is as follows:

protected intTryacquireshared (intacquires) {    returnnonfairtryacquireshared (acquires);
}finalintNonfairtryacquireshared (intacquires) { for (;;) { //get current semaphore value intAvailable =getState (); //calculate the current remaining value intRemaining = available-acquires; //returns if the current remaining is less than 0 or if the CAS setting is successful if(Remaining <0||compareandsetstate (available, remaining))returnremaining; }}

As the above code, first calculate the current semaphore value (available) minus the need to get the value (acquires) to get the remaining number of semaphores (remaining), if the remaining value is less than 0 indicates that the current number of semaphores can not meet the demand, then directly return negative numbers, The current thread is then put into the Aqs blocking queue and the current thread is suspended. If the remaining value is greater than 0, use the CAS operation to set the current semaphore value to the remaining value, and then return the remaining value. It is also possible to know that Nonfairsync is not fair, that the thread that first calls the Aquire method to get the semaphore is not necessarily the first to acquire the lock than the subsequent person.

Next we will look at the fairness of the Fairsync class is how to ensure fairness, the source code is as follows:

 protected intTryacquireshared (intacquires) {         for (;;) {            if(Hasqueuedpredecessors ())return-1; intAvailable =getState (); intRemaining = available-acquires; if(Remaining <0||compareandsetstate (available, remaining))returnremaining; } }

Can know the fairness or by hasqueuedpredecessors this method to do, the previous essay has been said that fairness is to see when the front node has a precursor node is also waiting to acquire the resource, if it is to give up the acquired power, and then the current thread will be put into the Aqs blocking queue, Otherwise, go get it. Hasqueuedpredecessors source code is as follows:

 Public Final Boolean hasqueuedpredecessors () {        = tail;          = head;        Node s;         return  null | | S.thread! = Thread.CurrentThread ());}

As shown in the preceding code, if the current thread node has a precursor node, returns True, otherwise if the current Aqs queue is empty or if the first node of the AQS node is false, if H = = T indicates that the current queue is empty, the direct return is False if H!=t and s =  = NULL indicates that there is an element to be queued as the first node of the AQS (recalling that the first element of the Enq function into the queue is a two-step operation, first creating a sentinel head node, and then inserting the first element behind the Sentinel node), then returns True if H!=t and s! = null and S.thread! = Thread.CurrentThread () indicates that the first element in the queue is not the current thread and returns TRUE.

2.void acquire (int permits) This method differs from acquire () in that the latter only needs to acquire a semaphore value, while the former acquires the specified permits, the source code is as follows:

 Public void Acquire (int  permits) throws Interruptedexception {        if0
Throw New illegalargumentexception (); sync.acquiresharedinterruptibly (permits);}

3.void acquireuninterruptibly () This method is similar to acquire () except that the method does not respond to interrupts, that is, when the front-thread calls the acquireuninterruptibly The interrupt () method that called the current thread during the Fetch resource process (which contains the block after it was blocked) sets the current thread's interrupt flag and returns the current thread without throwing a interruptedexception exception. The source code is as follows:

 Public void acquireuninterruptibly () {     sync.acquireshared (1);}

4.void acquireuninterruptibly (int permits) This method differs from acquire (int permits) in that the method does not respond to interrupts. The source code is as follows:

 Public void acquireuninterruptibly (int  permits) {        if0Throw  New  illegalargumentexception ();        Sync.acquireshared (permits); }

5.void release () The function of this method is to increase the current semaphore object's semaphore value by 1, if the current thread path because the call acquire method is blocked into the Aqs blocking queue, will be based on a fair policy to select a thread to activate, The active thread will attempt to obtain the newly added semaphore as follows:

 Public voidrelease () {//(1) arg=1Sync.releaseshared (1); }     PublicFinal Boolean releaseshared (intArg) {        //(2) Try to free up resources        if(tryreleaseshared (ARG)) {//(3) A successful resource release calls Park wakes up the first thread that hangs in the Aqs queuedoreleaseshared (); return true; }        return false; }    protectedFinal Boolean tryreleaseshared (intreleases) {         for (;;) {            //(4) Get current semaphore value            intCurrent =getState (); //(5) The current semaphore value is increased releases, this is increased by 1            intNext = current +releases; if(Next < current)//Removal processing                Throw NewError ("Maximum Permit count exceeded"); //(6) using CAs to guarantee the atomicity of updated semaphore values            if(Compareandsetstate (current, next))return true; }    }

As the above code can see the release () method in the Sync.releaseshared (1), you can know that the release method will only increase the semaphore value 1, the Tryreleaseshared method is an infinite loop, using CAs to ensure the release method to increase the signal volume by 1 atomic operation. When the Tryreleaseshared method increases the semaphore successfully executes the code (3), calls the Aqs method to activate the thread that was blocked because the acquire method was called.

6.void release (int permits) The method differs from the without parameter in that each invocation increases the permits on the original basis of the semaphore value, and the latter increases by 1 each time. The source code is as follows:

 Public void release (int  permits) {        if0thrownew  IllegalArgumentException ();        Sync.releaseshared (permits);}

It is also noted that sync.releaseshared is a shared method, which means that the semaphore is shared by the thread, the semaphore is not bound to a fixed thread, and multiple threads can use CAs to update the semaphore value without blocking.

Now that the principle is known, the following example is used to deepen the understanding of semaphore, as in the following example:

Package Com.hjc;import Java.util.concurrent.executorservice;import java.util.concurrent.executors;import Java.util.concurrent.Semaphore;/** * Created by Cong on 2018/7/8.*/ Public classSemaphoretest {//Create a Semaphore instance    Private Static volatileSemaphore Semaphore =NewSemaphore (0);  Public Static voidMain (string[] args) throws interruptedexception {Executorservice Executorservice= Executors.newfixedthreadpool (2); //join thread A to thread poolExecutorservice.submit (NewRunnable () { Public voidrun () {Try{System. out. println (Thread.CurrentThread () +" Over");                Semaphore.release (); } Catch(Exception e) {e.printstacktrace ();        }            }        }); //join thread B to thread poolExecutorservice.submit (NewRunnable () { Public voidrun () {Try{System. out. println (Thread.CurrentThread () +" Over");                Semaphore.release (); } Catch(Exception e) {e.printstacktrace ();        }            }        }); //wait for the child thread to finish executing and returnSemaphore.acquire (2); System. out. println ("All child thread over!"); //Close the thread poolExecutorservice.shutdown (); }}

The results of the operation are as follows:

Similar to Countdownlatch, our example above is to open two sub-threads in the main thread to execute, and so on after all child threads have finished executing, the main thread continues to run down.

As the above code first creates a semaphore instance, the constructor's input parameter is 0, the current semaphore counter is 0, and then the main function adds two thread tasks to the thread pool, each thread internally calls the semaphore's release method, which equals the count increment one, and finally in main The Acquire method that calls the semaphore inside the thread, the argument passed to 2 indicates that the thread that called the acquire method is blocked until the semaphore count becomes 2 o'clock.

See here also understand, if the construction of Semaphore time passed the parameter is N, in M threads call the release method of the semaphore, then the call acquire on M thread synchronization when the parameters passed should be m+n;

A comparative summary of the three countdownlatch,cyclicbarrier,semaphored:

The 1.CountDownLatch provides more flexible control through the counter, as long as the counter is detected as 0, regardless of whether the current thread ends the call to await the thread can execute down, compared to the use of jion must wait for the thread to finish execution after the main thread will continue to run more flexible.

2.CyclicBarrier can also achieve countdownlatch effect, but the latter when the counter becomes 0, it cannot be reused, while the former using the Reset method can be reset after reuse, the former for the same algorithm but the input parameters of different similar scenarios are applicable.

3. While the semaphore adopts a strategy of increasing the signal volume, it does not need to care about the number of threads that need to be synchronized at first, and so on when the call aquire specifies the number of synchronizations required, and provides a fairness strategy for acquiring the semaphore.

Semaphore signal Source Analysis of Java concurrent programming

Related Article

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: 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.