Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”. This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

Note: Gold digger diving monster starts today note: old back end is not water map

preface

Semaphore is a thread signal synchronization tool that can be used with ReentrantLock and synchronized. Semaphore is a thread signal synchronization tool that can be used with ReentrantLock. While the latter two allow only one thread to access a resource (more on the former next time), the former Semaphore allows multiple threads to access a resource simultaneously. We will continue to study from the four perspectives of introduction, method, scene and principle, and start right away.

A:

Official introduction: Counting semaphore. Conceptually, semaphores maintain a set of permissions. If necessary, each acquire block until the license is available, then acquire it. Adding a license to each release may free a blocked receiver. However, no actual license object is used; Semaphore simply calculates the amount available and acts accordingly. Semaphores are typically used to limit the number of threads that can access certain (physical or logical) resources.

Let me explain:

  • This is a semaphore tool that maintains a custom number of token signals.
  • We can use the acquire method to retrieve a token and continue with the business operation. If the thread is not retrieved, it will block until the token is retrieved or another thread has a interrupted operation.
  • Release releases the token.

    Method 2:

    The main methods of Semaphore are:

    Void acquire() // Permitting token can be passedCopy the code
    Void acquireUninterruptibly() void acquireUninterruptibly()// Permits can be passedCopy the code
    Boolean tryAcquire() // Attempt to acquire a token, return false, no block, permitting tokenCopy the code
    Void release() // Permitting token passedCopy the code
    Int availablePermits() // Number of available tokens currently availableCopy the code
    Int drainPermits() // Gets and returns all immediately available permitsCopy the code
    Void reducePermits(int Reduction) // Reduce some tokensCopy the code
    Boolean isFair() // whether the lock isFairCopy the code
    Boolean hasQueuedThreads() // Whether there are threads blocking waiting to get the tokenCopy the code
    Int getQueueLength() // Gets the number of blocked threadsCopy the code

    New Semaphore(2, true); new Semaphore(2, true); Fair lock objects can be created.

    Here’s a simple example to help you understand:

    @SneakyThrows static void singleSema(){ Semaphore semaphore = new Semaphore(1); new Thread(new Runnable() { @SneakyThrows @Override public void run() { System.out.println(thread.currentThread ().getName()+" get token in "); semaphore.acquire(); System.out.println(thread.currentThread ().getName()+" get token "); Thread.sleep((int)(Math.random()*1000)); semaphore.release(); System.out.println(thread.currentThread ().getName()+" release token "); }}, "zhang SAN ").start(); new Thread(new Runnable() { @SneakyThrows @Override public void run() { System.out.println(thread.currentThread ().getName()+" get token in "); semaphore.acquire(); System.out.println(thread.currentThread ().getName()+" get token "); Thread.sleep((int)(Math.random()*1000)); semaphore.release(); System.out.println(thread.currentThread ().getName()+" release token "); }}," li si ").start(); System.out.println(" Main thread gets token "); semaphore.acquire(); System.out.println(" main thread gets token "); Thread.sleep(100); System.out.println(" main thread release token "); semaphore.release(); }Copy the code

    This is a token passing operation, and the token resource can only be owned by one person at a time, just as lock and SYN implement. To see the results:

    So he's going to get the main thread of the token and he's going to get the main thread of the token and he's going to release the token and he's going to release the tokenCopy the code

    Only one person can have a token.

    Three: the scene

    Semaphore’s usage scenario is simple, with a controllable number of tokens, which can be used either to control thread exclusivity or to allow multiple threads to share a resource. To avoid blocking during use, the tryQcuire method can be used to obtain the token.

    Scenario 1: Thread resource monopolization

    As shown above, a SYN-like lock is achieved. Refer to the sample code above…

    Scenario 2: Thread resource sharing

    However, there were only three runways and there were five students in the whole school. In order to maximize the use of the runways, the school decided to let the next person enter the runways immediately after each student finished running, instead of starting after all the three runways were full.

    The source code:

    @SneakyThrows static void mulitSema(){ Semaphore semaphore = new Semaphore(3); New Thread(new Dog(semaphore)," Zhang SAN ").start(); New Thread(new Dog(semaphore)," 四").start(); New Thread(new Dog(semaphore)," King ").start(); New Thread(new Dog(semaphore)," horse ").start(); New Thread(new Dog(Semaphore)," Han ").start(); Thread.sleep(2000); while (semaphore.hasQueuedThreads()){ System.out.println("isfair::"+semaphore.isFair()+",availablepermits::"+semaphore.availablePermits() +",queuelength::"+semaphore.getQueueLength()+",tryacquire::"+semaphore.tryAcquire()); semaphore.release(); Thread.sleep(100); } system.out.println (" Thread end ::"+ thread.currentThread ().getName()); }Copy the code
    class Dog implements Runnable{ private Semaphore semaphore; public Dog(Semaphore semaphores){ semaphore = semaphores; } @Override public void run() { try { Thread.sleep((int)(Math.random()*1000)); System.out.println(thread.currentThread ().getName()+":: waiting for start "); semaphore.acquire(); System.out.println(thread.currentThread ().getName()+":: received start command "); Thread.sleep((int)(Math.random()*1000)); System.out.println(thread.currentThread ().getName()+":: running completed, release signal "); } catch (InterruptedException e) { e.printStackTrace(); }}}Copy the code

    Simply analyze the code and immediately notify the next student to occupy the track and start running when one student finishes running. Running results:

    Horse 6 waiting for starting instruction Horse 6 received the starting instruction Zhang SAN received the starting instruction Han Qi received the starting instruction Zhang SAN received the starting instruction Zhang SAN received the starting instruction Zhang SAN received the starting instruction Zhang SAN received the starting instruction Zhang SAN received the starting instruction Zhang SAN received the starting instruction Zhang SAN received the starting instruction Zhang SAN finished running, give the signal Horse 6 Finished running, Signal li Si :: Waiting for the starting command Han Qi :: Finished running, Release the signal Cathy: : are waiting to start command isfair: : false, availablepermits: : 0, queuelength: : 2, tryacquire: : : false, dick, and harry: received the launching instructions Isfair: : false, availablepermits: : 0, queuelength: : 1, tryacquire: : false Cathy: : received the launching instructions The main thread ends: : the main bill: : running, release signal Cathy: : running, release signalCopy the code

    We can see that the three runways have been fully utilized and the overall test time has been greatly shortened.

    Principle 4:

      First: initialization

    • When we construct the new Semaphore(2) method, we will create a synchronous blocking queue for an unfair lock, or we can build a synchronous blocking queue for a fair lock.
    • The number of incoming tokens is then assigned to the queue’s state, which represents the number of token signals currently remaining.

        Second: get the token

      • The current thread will attempt to obtain a token from the synchronization queue. The process of obtaining the token is to modify the state of the synchronization queue using atomic operations. When obtaining a token, the state is changed to state=state-1.
      • If state>=0, the token is successfully obtained.
      • If state<0, token acquisition is insufficient, a Node Node is created and added to the blocking queue until tokens are available.

          Third: Release the token

        • The thread releases a token and changes state to state=state+1, indicating that the token has been released successfully. If the token fails to be released or returns false, you need to try again.
        • When a token is released, the system wakes up a waiting blocked thread.
        • The awakened thread will calculate state=state-1 and judge state>=0 to indicate successful token acquisition.

          Thanks for reading and feel free to leave a comment in the comments section.