Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Java semaphores: permit accounting and bounded access

Last updated: 29 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

A Semaphore maintains a permit count and can block or reject callers when the permitted number of simultaneous users is exhausted.

Java 8+. This is a complete program using JDK classes.

Account for successful acquisition

A service has two external connections available for a particular operation. A semaphore can limit admission to two callers, but it does not create or select those connections. Resource selection still needs its own protected pool data structure.

Release only after this caller successfully acquired a permit. A release after a failed tryAcquire adds a permit that no operation owned, expanding capacity. The example makes that branch visible: the rejected third attempt does not enter a finally block that releases anything.

A semaphore is not an ownership-aware mutex. Another thread can release a permit, and the object does not verify that the caller acquired it earlier. Keep ownership in the operation structure. A fair semaphore can improve admission ordering under its contract, but fairness is not a latency bound or a throughput guarantee.

Wait budgets are part of admission

For request handling, use timed acquisition when callers have a deadline. A method that waits indefinitely can exhaust the server threads even though it successfully limits downstream concurrency. Interruption must also stop waiting rather than turn a cancelled request into another admitted task.

Working program

Java
import java.util.concurrent.Semaphore;
public class ConnectionAdmission {
    public static void main(String[] args) {
        Semaphore permits = new Semaphore(2);
        boolean first = permits.tryAcquire();
        boolean second = permits.tryAcquire();
        System.out.println(first);
        System.out.println(second);
        System.out.println(permits.tryAcquire());
        if (first) permits.release();
        if (second) permits.release();
        System.out.println(permits.availablePermits());
    }
}

Output

Output
true
true
false
2

Costs and boundaries

The object has a compact permit-accounting state, while waiting callers add scheduling and queueing work. This fixture does no external I/O and measures no downstream throughput. A caller must budget for both admission waiting and the admitted operation.

Common Mistakes

  • Do not release after a rejected acquisition.
  • Permit capacity does not make a mutable connection safe to share.
  • A fair flag does not guarantee a task finishes by a deadline.

Read next

Counter invariants, Worker admission.

java
semaphores
Storage details