The current limiting tool provided in JUC-Semaphore (semaphore)

The current limiting tool provided in JUC-Semaphore (semaphore)

Under the JUC package, there is a Semaphore class, which is translated into a semaphore. Semaphore (semaphore) is used to control the number of threads that access specific resources at the same time. It coordinates various threads to ensure the reasonable use of common resources. Semaphore is a bit similar to locks (synchronized, Lock). The difference is that locks only allow one thread to access a resource at the same time, while Semaphore can control multiple threads to access a resource at the same time.

Semaphore (semaphore) is not unique to the Java language, almost all concurrent languages have it. So there is a concept of a semaphore model , as shown in the following figure:

The semaphore model is relatively simple and can be summarized as: a counter, a queue, and three methods .

Counter: Record how many resources can be run to access resources currently.

Queue: the thread to access the resource

3.methods :

  • init() : Initialize the value of the counter, but it is how many threads are allowed to access resources at the same time.
  • up() : The counter is incremented by 1, when a thread returns the resource, if the value of the counter is greater than or equal to 0, a thread will be awakened from the waiting queue
  • down() : The counter is decremented by 1. When a thread is occupying resources, if the value of the counter is less than 0 at this time, the thread will be blocked.

These three methods are all atomic, and the implementer guarantees the atomicity. For example, in the Java language, Semaphore under the JUC package implements the semaphore model, so Semaphore guarantees the atomicity of these three methods.

Semaphore implements the semaphore model based on the AbstractQueuedSynchronizer interface. AbstractQueuedSynchronizer provides a basic framework based on FIFO queues that can be used to build locks or other related synchronization devices. It uses an int to represent the state, and manipulates the state in a manner similar to acquire and release. For more introduction about AbstractQueuedSynchronizer, you can click on the link:

ifeve.com/introduce-a...

The implementation class of AbstractQueuedSynchronizer in the Semaphore class is as follows:

    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 1192457210091910933L;

        Sync(int permits) {
            setState(permits);
        }

        final int getPermits() {
            return getState();
        }

        final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }

        protected final boolean tryReleaseShared(int releases) {
            for (;;) {
                int current = getState();
                int next = current + releases;
                if (next < current) //overflow
                    throw new Error("Maximum permit count exceeded");
                if (compareAndSetState(current, next))
                    return true;
            }
        }

        final void reducePermits(int reductions) {
            for (;;) {
                int current = getState();
                int next = current - reductions;
                if (next > current) //underflow
                    throw new Error("Permit count underflow");
                if (compareAndSetState(current, next))
                    return;
            }
        }

        final int drainPermits() {
            for (;;) {
                int current = getState();
                if (current == 0 || compareAndSetState(current, 0))
                    return current;
            }
        }
    }
 

In the Semaphore class, two types of semaphores are implemented: fair semaphores and unfair semaphores . A fair semaphore means that everyone is in line, first come first, and unfair semaphores are not necessarily first come first. Allow Jump in line. Unfair semaphores are more efficient, so unfair semaphores are used by default. Specifically, you can view the source code of the Semaphore class.

In the Semaphore class, there are mainly the following methods:

// 
public Semaphore(int permits);
// 
public void acquire() throws InterruptedException;
// 1 true false 
public boolean tryAcquire();
// 
public void release();
 

The implementation of the Semaphore class is almost understood. You may have questions about the application scenarios of Semaphore? Semaphore can be used to limit current (flow control). In some scenarios where public resources are limited, Semaphore can come in handy. For example, when doing log cleaning, there may be dozens of threads in concurrent cleaning, but when the cleaned data is stored in the database, only 10 connection pools may be allocated to the database, so the number of threads on both sides is not equal, we It must be ensured that only 10 threads can get the database link at the same time, otherwise there will be a large number of threads that cannot connect to the database.

Use Semaphore semaphore to simulate this operation, the code is as follows:

public class SemaphoreDemo {
    /**
     * semaphore  
     *
     *   5  
     */

    private static final int THREAD_COUNT = 30;

    private static ExecutorService threadPool = Executors
            .newFixedThreadPool(THREAD_COUNT);
	//  5 
    private static Semaphore s = new Semaphore(5);

    public static void main(String[] args) {
        for (int i = 0; i < THREAD_COUNT; i++) {
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        // 
                        s.acquire();
                        System.out.println(Thread.currentThread().getName()+"   ,"+ new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format( new Date()));
                        // 
                        Thread.sleep(2000);
                        // 
                        s.release();
                    } catch (InterruptedException e) {
                    }
                }
            });
        }
		// 
        threadPool.shutdown();
    }
}
 

The operation effect is as follows:

From the results, it can be seen that only 5 threads are executing per second, which is in line with our expectations.

Well, the content about Semaphore is over. For more details, please refer to the relevant information and read the Semaphore source code. I hope this article is helpful to your study or work.

Thank you for reading, and good luck.

At last

At present, many big guys on the Internet have articles about Semaphore (semaphore). If there are any similarities, please bear with me. Originality is not easy, codewords are not easy, and I hope everyone will support me. If there are any mistakes in the article, I hope to bring it up, thank you.