AQS series (six) - Semaphore usage and principle

Foreword

    Semaphore is a utility class JUC package for concurrency control, and give examples of common scenarios: There are three computers five people, each person must use their own computers to register an account, then initially only at the same time there are three people to operate a computer Register for an account which was operating three people over the two remaining people who can take up computer to register their accounts. This is a classic use Semaphore scene, with concurrent locking bit like, but we only allow concurrent locking the same time there is a thread of execution, and control Semaphore locking is allowed at the same time have a specified number of threads execute simultaneously, more than this the number will lock control.

First, use the sample

. 1  public  static  void main (String [] args) {
 2          Semaphore semaphore = new new Semaphore (3 ); // in Comparative example 3 above computer
 3          for ( int I = 0; I <. 5; I ++ ) {// Comparative examples of the above five people
 . 4              new new the Thread (() -> {
 5                  the try {
 . 6                      Semaphore.acquire (. 1 ); // Note acquire values may pass any value> = an integer of 0
 . 7                  } the catch (InterruptedException E) {
 . 8                      e.printStackTrace ();
 . 9                  }
 10                 System.out.println(Thread.currentThread().getName() + " acquire 1");
11                 try {
12                     Thread.sleep(2000);
13                 } catch (InterruptedException e) {
14                     e.printStackTrace();
15                 }
16                 System.out.println(Thread.currentThread().getName() + "release 1");
17                 semaphore.release(1);
18             }).start();
19         }
20     }

    Implementation of the results:

 1 Thread-0 acquire 1
 2 Thread-2 acquire 1
 3 Thread-1 acquire 1
 4 Thread-1release 1
 5 Thread-2release 1
 6 Thread-0release 1
 7 Thread-4 acquire 1
 8 Thread-3 acquire 1
 9 Thread-4release 1
10 Thread-3release 1

    It can be seen at the same time only three threads to acquire the lock, after three executing the release, and the remaining two dishes executed to acquire the lock. Let's see how the source code is implemented.

Second, the source code implementation

1, Semaphore constructor

1     public Semaphore(int permits) {
2         sync = new NonfairSync(permits);
3     }
4 
5     public Semaphore(int permits, boolean fair) {
6         sync = fair ? new FairSync(permits) : new NonfairSync(permits);
7     }

    Can be seen, there are two Semaphore constructors, a default value is only passing unfair lock, another may specify a fair or non-fair lock latch. It permits eventually assigned to the state variables of AQS.

2, acquire (1) Method

1 public void acquire(int permits) throws InterruptedException {
2         if (permits < 0) throw new IllegalArgumentException();
3         sync.acquireSharedInterruptibly(permits);
4     }

    This method also calls the template method of AQS:

1 public final void acquireSharedInterruptibly(int arg)
2             throws InterruptedException {
3         if (Thread.interrupted())
4             throw new InterruptedException();
5         if (tryAcquireShared(arg) < 0)
6             doAcquireSharedInterruptibly(arg);
7     }

1) Check tryAcquireShared implementation methods

    Look at the non-lock fair access to:

. 1  Final  int nonfairTryAcquireShared ( int Acquires) {
 2              for (;;) {
 . 3                  int Available = getState ();
 . 4                  int Remaining Available = - Acquires; Remaining // if negative, indicating insufficient current remaining amount of the signal, it is necessary blocking
 . 5                  IF (remaining <0 ||
 . 6                      compareAndSetState (available, Remaining)) // if the remaining <0 return directly, not take CAS; if more than 0, indicating that the semaphore is also enough, can take CAS subtracted semaphore remaining, greater than 0 if successful returns
 . 7                      return Remaining;
 . 8              }
 . 9          }

    Look lock fair access to:

. 1  protected  int tryAcquireShared ( int Acquires) {
 2              for (;;) {
 . 3                  IF (hasQueuedPredecessors ()) // judgment is not in the first team, is not the case return directly -1
 . 4                      return -1 ;
 . 5                  int Available = getState () ; // pass the logic behind the lock acquisition logic unfair
 . 6                  int Remaining Available = - acquires;
 . 7                  IF (Remaining <0 ||
 . 8                      compareAndSetState (Available, Remaining))
 . 9                      return Remaining;
 10              }
 . 11          }

    We can see, regardless of non-equity and equity-locking lock, when the lock is enough to determine the current state minus, minus a negative return if the failure to acquire the lock, is a positive signal before walking CAS original amount deducted to return to acquire the lock success. A process of reducing state when locked.

2)、doAcquireSharedInterruptibly

    This method is also implemented in the AQS logic repeated, no longer explained.

3, release (1) Method

1 public void release(int permits) {
2         if (permits < 0) throw new IllegalArgumentException();
3         sync.releaseShared(permits);
4     }

    Also called template method releaseShared AQS in:

1 public final boolean releaseShared(int arg) {
2         if (tryReleaseShared(arg)) {
3             doReleaseShared();
4             return true;
5         }
6         return false;
7     }

    Wherein tryReleaseShared implemented in Sync Semaphore class, as follows:

. 1  protected  Final  Boolean tryReleaseShared ( int Releases) {
 2              for (;;) {
 . 3                  int Current = getState ();
 . 4                  int Next Current = + Releases; // current state by adding to release Releases
 . 5                  IF (Next <Current ) // overflow 
. 6                      the throw  new new Error ( "the permit the Maximum COUNT exceeded Number" );
 . 7                  IF (compareAndSetState (Current, Next)) // add with CAS to state
 . 8                      return  to true ;
 . 9              }
 10          }

    Another way to read before doReleaseShared, not go into details here.

III Summary

    Semaphore Semaphore class based on a shared lock AQS realization, fair and unfair lock lock both versions. It differs in that the locking and releasing the lock and the lock release lock common with anti, ReentrantLock ReentrantReadWriteLock and lock are both in state + 1, the lock releasing state-1, and when the lock state is Semaphore Save, state overtime releases the lock.

    In addition, if it can acquire (2), release (1), and the amount of signal that is released can be obtained inconsistent, just need to pay attention to the amount of signal do not lead to the release of too little follow-up tasks not obtain sufficient quantities permanently blocked.

Guess you like

Origin www.cnblogs.com/zzq6032010/p/12076687.html