Under the JUC package, there is a Semaphore class, which translates to Semaphore. Semaphore is used to control the number of threads accessing a particular resource at the same time. It ensures proper use of common resources by coordinating threads. Semaphore is similar to synchronized, except that a Lock allows only one thread to access a resource at a time, whereas a Semaphore allows multiple threads to access a resource at a time.

Semaphore (Semaphore) is not unique to the Java language and is found in almost all concurrent languages. So there is the concept of a semaphore model, as shown below:

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

Counter: Records how many resources can still be run to access resources.

Queue: The thread to access the resource

Three methods:

  • Init () : Initializes the value of the counter, which is how many threads are allowed to access the resource simultaneously.
  • Up () : the counter is incremented by 1 to wake up a thread from the wait queue if the counter is greater than or equal to 0 when a thread returns the resource
  • Down () : If the count is less than 0, the thread will be blocked.

All three methods are atomic, which is guaranteed by the implementor. For example, in the Java language, Semaphore under the JUC package implements the Semaphore model, so Semaphore guarantees atomicity for all three methods.

Semaphore is based on the model of “AbstractQueuedSynchronizer interface implementation Semaphore. AbstractQueuedSynchronizer provides a based on FIFO queue, can be used to build the lock or other related synchronizer based framework, use a int to represent the state, through the way similar to acquire and release to manipulate state. More introduction on AbstractQueuedSynchronizer, can click on the link:

Ifeve.com/introduce-a…

AbstractQueuedSynchronizer Semaphore classes in the implementation class is as follows:

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

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

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

        final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    returnremaining; }}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(a) {
            for (;;) {
                int current = getState();
                if (current == 0 || compareAndSetState(current, 0))
                    returncurrent; }}}Copy the code

In Semaphore class, two kinds of Semaphore are implemented: fair Semaphore and unfair Semaphore. Fair Semaphore means that everyone lines up and gets first, and unfair Semaphore means that queue jumping is not necessarily allowed. An unfair semaphore is more efficient, so the default is to use an unfair semaphore. For details, see Semaphore class implementation source code.

The Semaphore class has the following methods:

// Constructor, which takes the number of permits to create a semaphore
public Semaphore(int permits);
// Obtaining permission from a semaphore is equivalent to obtaining execution authority
public void acquire(a) throws InterruptedException;
// Try to obtain a license. Return true if the license was obtained successfully or false if the license was not obtained
public boolean tryAcquire(a);
// Return permission to the semaphore
public void release(a);
Copy the code

The Semaphore class implementation is pretty much there. You may be wondering what is the application scenario of Semaphore? Semaphore can be used for flow limiting (flow control), which can come in handy in scenarios where common resources are limited. In doing log when cleaning, for example, there may be dozens of thread in concurrent cleaning, but will be cleaning the data into database, may only assign database 10 connection pool, so the number of threads on both sides of the unequal, we must make the pledge that we shall only have 10 threads access database links at the same time, otherwise it will exist a large number of threads cannot link on the database.

To simulate this operation, use Semaphore Semaphore as follows:

public class SemaphoreDemo {
    /** * Semaphore, which can limit the flow ** to simulate concurrent database operations, has 30 requests at the same time, but the system can only process 5 */ per second

    private static final int THREAD_COUNT = 30;

    private static ExecutorService threadPool = Executors
            .newFixedThreadPool(THREAD_COUNT);
	// Initialize the semaphore with the number 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(a) {
                    try {
                        // Get permission
                        s.acquire();
                        System.out.println(Thread.currentThread().getName()+"Complete database operation,"+ new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format( new Date()));
                        // Sleep for 2 seconds
                        Thread.sleep(2000);
                        // Release permission
                        s.release();
                    } catch (InterruptedException e) {
                    }
                }
            });
        }
		// Close the connection poolthreadPool.shutdown(); }}Copy the code

The running effect is as follows:

From the results, you can see that only five threads are executing per second, which is what we expect.

Well, that’s the end of Semaphore. For more details, please refer to the relevant resources and read the Semaphore source code. I hope this article is helpful to your study or work.

Thank you for reading and good luck.

The last

Many of the big names on the Internet have published articles about Semaphore. Please bear with me if they are similar. The original is not easy, the code word is not easy, but also hope you support. If there are mistakes in the article, please also put forward, thank you.