[JAVA core knowledge] 15.3: thread controller Semaphore

Posted by manimoor on Mon, 31 Jan 2022 02:37:04 +0100

brief introduction

A thread controller for resource control under multithreading. Much like lock synchronization, the difference between lock synchronization and lock synchronization is that a lock locks a resource, and only one thread can operate the resource at the same time. Semaphore locks a batch of resources. At the same time, only a specified number of threads are allowed to perform operations.
It is also similar to thread pool. The difference is that the thread waiting in the thread pool is not running, and this thread is already running and competing.
It is applicable when the amount of resources is less than the amount of threads. For example, a connection only allows 10 threads to connect at the same time. Now there are 100 threads to perform this connection operation, you can use Semaphore to control it.

common method

  • Semaphore (int permissions): construct the method. The input parameter is the permission, that is, several threads are allowed to act at the same time. Default to unfair
  • Semaphore (int permissions, Boolean Fair): input parameter 1 of the construction method is the allowable quantity, and input parameter 2 is whether the competition is fair. true is fair
  • void acquire() throws InterruptedException: to get a license, wait until you get it. InterruptedException if interrupted during waiting
  • Void acquireunteruptibly(): to get a license, wait until you get it, and ignore the interrupt command
  • boolean tryAcquire(): try to obtain a license. If it is obtained, it returns true. If it is not obtained, it returns false
  • Boolean try acquire (long timeout, timeunit unit): try to obtain a license within a specified time. If it is obtained, it returns true, and if it is not obtained, it returns false
  • void release(): release a license without holding a license. That is, the license release order can still be issued without holding the license
  • Void acquire (int permissions) throws InterruptedException: to obtain a specified number of licenses, wait until you get them. InterruptedException if interrupted during waiting
  • Void acquire uninterruptible (int permits): to obtain a specified number of licenses, wait until you get them, and ignore the interrupt command
  • Boolean tryacquire (int permissions): to obtain a specified number of licenses, return true if obtained, and false if not obtained
  • Boolean tryacquire (int permissions, long timeout, timeunit unit): try to obtain a specified number of licenses within a specified time. If you get it, return true; if you don't get it, return false
  • void release(int permits): release a specified number of licenses without holding a specified number of licenses. Two or more licenses can be released even if you don't have a license or only one license.
  • Int availablepermissions(): current available licenses
  • int drainPermits(): obtain all licenses and return the obtained licenses
  • Fair competition: fair competition
  • final boolean hasQueuedThreads(): whether there are threads competing at present
  • final int getQueueLength(): the length of the current contention queue

Examples

package sync;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Semaphore;

public class SemaphoreTest {

    public static void main(String[] args) {
        final Semaphore s = new Semaphore(2);  // If the input parameter is 2, it is a normal 3-task and two licensing processes are transferred. If it is 1, it can be verified that the license can be released without obtaining the license
        Runnable r1 = new Runnable() {
            
            @Override
            public void run() {
                try {
                    System.out.println("1 Request resource - " + showNow());
                    s.acquire();
                    System.out.println("1 No. get resources - " + showNow());
                    System.out.println("1 Start working on the 1st - " + showNow());
                    Thread.sleep(5000);
                    System.out.println("1 The work is finished,Start releasing resources - " + showNow());
                    s.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        
        Runnable r2 = new Runnable() {
            
            @Override
            public void run() {
                try {
//                    Thread.sleep(200);  //  Ensure that the execution sequence is 1.2.3
                    System.out.println("2 Request resource - " + showNow());
                    s.acquire();  // If you comment out this place, open the code to ensure the release order and set the license to one, the operation will find that No. 1 holds the resource work first, and then 2 can release the license without obtaining the license, so that 3 can obtain the license to start execution before 1 releases the license
                    System.out.println("2 No. get resources - " + showNow());
                    System.out.println("2 Start working on the 1st - " + showNow());
                    Thread.sleep(1000);
                    System.out.println("2 The work is finished,Start releasing resources - " + showNow());
                    s.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        
        Runnable r3 = new Runnable() {
            
            @Override
            public void run() {
                try {
//                    Thread.sleep(500);//  Ensure that the execution sequence is 1.2.3
                    System.out.println("3 Request resource - " + showNow());
                    s.acquire();
                    System.out.println("3 No. get resources - " + showNow());
                    System.out.println("3 Start working on the 1st - " + showNow());
                    Thread.sleep(1000);
                    System.out.println("3 The work is finished,Start releasing resources - " + showNow());
                    s.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        
        new Thread(r1).start();
        new Thread(r2).start();
        new Thread(r3).start();
    }

    private static String showNow(){
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
        return sdf.format(new Date());
    }
    
}

Operation results:

2 Request resource - 17:23:48.107
1 Request resource - 17:23:48.107
2 No. get resources - 17:23:48.107
3 Request resource - 17:23:48.107
2 Start working on the 1st - 17:23:48.107
1 No. get resources - 17:23:48.107
1 Start working on the 1st - 17:23:48.107
2 The work is finished,Start releasing resources - 17:23:49.107
3 No. get resources - 17:23:49.108
3 Start working on the 1st - 17:23:49.108
3 The work is finished,Start releasing resources - 17:23:50.108
1 The work is finished,Start releasing resources - 17:23:53.107

PS:
[JAVA core knowledge] series navigation [constantly updating...]
Previous navigation: 15.2: thread controller CyclicBarrier
Part 2 notice: 16: volatile keyword
Welcome to

Topics: Java Multithreading Concurrent Programming