A Semaphore in Java Concurrency is a utility that controls access to a shared resource using a set of virtual permits. Unlike a standard mutual exclusion lock (Mutex) which only allows one thread, a Semaphore can allow multiple threads to access a resource in parallel up to a configured limit.
Imagine an ATM bank vestibule that contains exactly 2 ATM machines inside. A security guard stands outside holding exactly 2 keys (permits):
- Alice arrives first. The guard hands her a key, and she enters the booth (1 permit remaining).
- Bob arrives second. The guard hands him the second key, and he enters (0 permits remaining).
- Charlie arrives third. Since there are no keys left, the guard makes him wait outside in a blocked queue.
- Once Alice finished her transaction and leaves, she returns the key (releases permit) to the guard. The guard immediately hands it to Charlie, who can now enter.
Implementing Semaphore in Java
Using semaphore.acquire() locks a thread if no permits are available, and
semaphore.release() returns a permit to the pool:
package io.practise.threadsExample;
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
// Only 2 threads can access the resource simultaneously
static Semaphore semaphore = new Semaphore(2);
public static void main(String[] args) {
new MyAtmThread("Alice").start();
new MyAtmThread("Bob").start();
new MyAtmThread("Charlie").start();
}
static class MyAtmThread extends Thread {
public MyAtmThread(String name) {
super(name);
}
@Override
public void run() {
try {
System.out.println(getName() + " is waiting to enter the ATM booth...");
// Acquire a permit
semaphore.acquire();
System.out.println(getName() + " entered the booth and is doing transactions.");
Thread.sleep(2000); // Simulate transaction processing
System.out.println(getName() + " is leaving the ATM booth.");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// Always release permit in finally block to prevent thread deadlocks
semaphore.release();
}
}
}
}
Conclusion
Semaphores are highly useful for rate-limiting calls to external APIs, managing database connection pools, or shielding expensive physical server resources from concurrent overload.