Mastering Java Semaphore: Controlling Concurrent Access with a Parking‑Lot Demo
This article explains the concept and internal design of Java's Semaphore, shows how to create fair or non‑fair instances, details the acquire and release operations, compares fairness strategies, and provides a complete parking‑lot example with runnable code and output.
What Is a Semaphore?
A semaphore is a counting synchronizer that controls access to a set of shared resources. Each acquire() decrements the permit count, blocking when the count reaches zero, while each release() increments the count, potentially unblocking waiting threads.
Internal Structure
In the JDK, java.util.concurrent.Semaphore is built on top of the AbstractQueuedSynchronizer (AQS). It contains two inner synchronizer classes:
FairSync – implements a first‑in‑first‑out acquisition order.
NonfairSync – acquires permits without checking the queue head, offering higher throughput.
Both extend the abstract Sync class, which itself extends AQS.
Constructors
Semaphore(int permits)– creates a semaphore with the given number of permits and a non‑fair default policy. Semaphore(int permits, boolean fair) – creates a semaphore with the given permits and the specified fairness policy.
Key Methods
acquire()
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}The method delegates to AQS.acquireSharedInterruptibly(int), which repeatedly invokes tryAcquireShared(int) on the concrete Sync implementation (fair or non‑fair) until the permit can be obtained or the thread is interrupted.
release()
public void release() {
sync.releaseShared(1);
}This calls AQS.releaseShared(int), which in turn invokes tryReleaseShared(int) on the synchronizer to add a permit and possibly wake a waiting thread.
Fair vs. Non‑fair Acquisition
Fair mode checks whether the current thread is at the head of the CLH queue before attempting to acquire a permit:
protected int tryAcquireShared(int acquires) {
if (hasQueuedPredecessors())
return -1; // not first, fail fast
int available = getState();
int remaining = available - acquires;
if (remaining < 0 || compareAndSetState(available, remaining))
return remaining;
return -1;
}Non‑fair mode skips the queue‑head check, directly attempting a CAS update:
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 || compareAndSetState(available, remaining))
return remaining;
}
}Parking‑Lot Example
The following program models a parking lot with five spaces using a semaphore. Cars (threads) acquire a permit to enter, stay for a random time, then release the permit when leaving.
public class SemaphoreTest {
public static class Parking {
private Semaphore semaphore;
public Parking(int count) { semaphore = new Semaphore(count); }
public void park() throws InterruptedException {
semaphore.acquire();
long time = (long)(Math.random() * 10);
System.out.println(Thread.currentThread().getName() + " enters, stays " + time + " sec");
Thread.sleep(time * 1000);
System.out.println(Thread.currentThread().getName() + " leaves");
}
public void leave() { semaphore.release(); }
}
public static class Car extends Thread {
private final Parking parking;
public Car(Parking p) { this.parking = p; }
public void run() {
try { parking.park(); } finally { parking.leave(); }
}
}
public static void main(String[] args) {
Parking parking = new Parking(5);
for (int i = 0; i < 10; i++) {
new Car(parking).start();
}
}
}Running the program produces output similar to the screenshot below, showing cars waiting when permits are exhausted and proceeding as spots become free.
This demonstration illustrates how a semaphore can be used to limit concurrent access to a finite resource pool, a pattern common in server‑side Java applications.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
