Understanding Java Semaphore for Rate Limiting and Concurrency Control

This article explains the purpose and usage of Java's Semaphore class, demonstrates how it can be applied for rate limiting with real‑world analogies, provides a complete parking‑lot example with source code, and discusses fairness modes and additional Semaphore APIs.

Full-Stack Internet Architecture
Full-Stack Internet Architecture
Full-Stack Internet Architecture
Understanding Java Semaphore for Rate Limiting and Concurrency Control

Basic Information

Name: Semaphore

Chinese name: (计数)信号量

Introduced in: JDK 1.5

Origin: java.util.concurrent (JUC) package

Purpose: A Java synchronizer that manages permits; threads call acquire() to obtain a permit (blocking if none are available) and release() to return a permit, with the maximum number of permits defined at creation.

Professional Skill

The core skill of Semaphore is "permit management", which can be used to implement rate‑limiting functionality easily.

What Is Rate Limiting?

Rate limiting controls the maximum number of concurrent accesses to a resource, similar to limiting the number of visitors entering a scenic spot or the number of cars allowed on a road during peak hours, thereby preventing overload and ensuring stable operation.

Implementing Rate Limiting with Semaphore

When a Semaphore is created, the number of permits sets the upper bound for concurrent access. Calls to release() add permits, while acquire() blocks until a permit becomes available, effectively throttling the flow of requests.

Project Example

The following code demonstrates using a Semaphore to limit a parking‑lot to two spaces while five cars (threads) compete for entry.

import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * Author: Lei Ge
 * By: Java Chinese Community
 */
public class SemaphoreExample {
    // Create a semaphore with 2 permits (2 parking spaces)
    static Semaphore semaphore = new Semaphore(2);

    public static void main(String[] args) {
        // Fixed thread pool of 5 threads (5 cars)
        ExecutorService threadPool = Executors.newFixedThreadPool(5);

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                String tname = Thread.currentThread().getName();
                System.out.println(String.format("Driver: %s, waiting outside, time: %s", tname, new Date()));
                try {
                    Thread.sleep(100); // Simulate arrival delay
                    semaphore.acquire(); // Block until a permit is available
                    System.out.println(String.format("Driver: %s, entered parking lot, time: %s", tname, new Date()));
                    Thread.sleep(1000); // Simulate parking duration
                    System.out.println(String.format("Driver: %s, leaving parking lot, time: %s", tname, new Date()));
                    semaphore.release(); // Return the permit
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        // Submit five tasks
        threadPool.submit(runnable);
        threadPool.submit(runnable);
        threadPool.submit(runnable);
        threadPool.submit(runnable);
        threadPool.submit(runnable);

        threadPool.shutdown();
    }
}

Running the program shows that at most two drivers can be inside the parking lot simultaneously; the others wait until a permit is released, thereby achieving rate limiting.

Personal Evaluation

Semaphore provides two modes: fair (FIFO) and non‑fair (default). The non‑fair mode offers higher performance because a newly released permit may be granted to a thread that is ready, without strictly following the arrival order.

Fair vs. Non‑Fair Mode

Fair mode respects the order of acquire() calls (first‑in‑first‑out). Non‑fair mode allows a thread that happens to be ready at the moment of release to obtain the permit, which can improve throughput.

Using Fair Mode

Semaphore offers two constructors; the second one accepts a boolean fair flag. Setting this flag to true creates a fair semaphore.

public Semaphore(int permits) {
    sync = new NonfairSync(permits); // default non‑fair
}

public Semaphore(int permits, boolean fair) {
    sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}

Additional Semaphore Methods

int availablePermits(): returns the current number of permits.

int getQueueLength(): returns the number of threads waiting for permits.

boolean hasQueuedThreads(): checks if any threads are waiting.

boolean isFair(): indicates whether the semaphore is fair.

void release(int permits): releases a given number of permits.

boolean tryAcquire(): attempts to acquire a permit without blocking.

boolean tryAcquire(int permits): attempts to acquire the specified number of permits.

boolean tryAcquire(int permits, long timeout, TimeUnit unit): tries to acquire permits within a timeout.

boolean tryAcquire(long timeout, TimeUnit unit): tries to acquire a single permit within a timeout.

void reducePermits(int reduction): protected method to reduce the number of permits.

Collection getQueuedThreads(): protected method returning the waiting threads.

Conclusion

Semaphore manages a set of permits, defaulting to a non‑fair strategy for higher performance. The key methods are release() (to add a permit) and acquire() (to block until a permit is available). By controlling permits, Semaphore provides an effective way to implement rate limiting in concurrent Java applications.

Recommended Reading

Kafka Principles: Illustrated Architecture

Architecture Design Methodology

Kafka from an Interview Perspective

Database and Cache Dual‑Write Consistency

Comprehensive Load Balancing Principles

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendJavaconcurrencysemaphorerate limiting
Full-Stack Internet Architecture
Written by

Full-Stack Internet Architecture

Introducing full-stack Internet architecture technologies centered on Java

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.