java 27 lines · 6 steps

Bounding concurrency with a Semaphore in Java

A Semaphore caps how many tasks run at once and rejects callers that wait too long.

Explained by highlit
1public class RequestThrottler {
2 
3 private final Semaphore permits;
4 private final long acquireTimeoutMillis;
5 
6 public RequestThrottler(int maxInFlight, long acquireTimeoutMillis) {
7 this.permits = new Semaphore(maxInFlight, true);
8 this.acquireTimeoutMillis = acquireTimeoutMillis;
9 }
10 
11 public <T> T execute(Callable<T> task) throws Exception {
12 boolean acquired = permits.tryAcquire(acquireTimeoutMillis, TimeUnit.MILLISECONDS);
13 if (!acquired) {
14 throw new RejectedExecutionException(
15 "Request rejected: " + permits.getQueueLength() + " callers waiting, no permits available");
16 }
17 try {
18 return task.call();
19 } finally {
20 permits.release();
21 }
22 }
23 
24 public int availablePermits() {
25 return permits.availablePermits();
26 }
27}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1A fair Semaphore is a clean primitive for capping in-flight work without spinning up thread pools.
  2. 2Bounded acquire timeouts turn silent queuing into fast, explicit rejection under overload.
  3. 3Releasing in a finally block guarantees permits return even when the task throws.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Bounding concurrency with a Semaphore in Java — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code