Java Semaphore Decoupling: Thread-Agnostic Permits vs. Lock Coupling
This article explains Java Semaphore's core decoupling property—where any thread can acquire or release permits—contrasting it with ReentrantLock's thread-owned locking, demonstrates with Java 17 code examples, and shows real-world rate-limiting applications in Sentinel, Dubbo, and Tomcat.
The article opens by framing semaphore understanding around "limiting resources," a core concern in concurrent programming. It argues that the key characteristic of a semaphore is not merely its permit counter but its decoupling property: a semaphore only recognizes quantity, not thread identity. Any thread can increment or decrement the internal counter; the semaphore neither records nor validates which thread performs the operation.
Decoupling Demonstrated with Java 17 Code
A SemaphoreDecouplingDemo illustrates this decoupling. The semaphore starts with zero permits, forcing a cross-thread release-acquire dependency:
import java.util.concurrent.Semaphore;
public class SemaphoreDecouplingDemo {
public static void main(String[] args) throws InterruptedException {
// Initial permits = 0, forcing cross-thread release-acquire dependency
Semaphore semaphore = new Semaphore(0);
// Consumer thread: only acquires a permit
Thread consumer = new Thread(() -> {
try {
System.out.println("[Consumer] Attempting to acquire permit... blocking");
semaphore.acquire(); // Blocks until a permit is available
System.out.println("[Consumer] Permit acquired! Processing task");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}, "Consumer");
// Producer thread: only releases a permit, completely independent of consumer
Thread producer = new Thread(() -> {
try {
// Simulate async resource preparation latency
Thread.sleep(500);
System.out.println("[Producer] Resource ready, releasing permit");
semaphore.release(); // Permit created by a different thread
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}, "Producer");
consumer.start();
producer.start();
consumer.join();
producer.join();
}
}Execution output confirms the handoff:
[Consumer] Attempting to acquire permit... blocking
[Producer] Resource ready, releasing permit
[Consumer] Permit acquired! Processing taskThe consumer only calls acquire(); the producer only calls release(). They share no direct reference, yet coordination succeeds because the semaphore is a shared counter indifferent to thread ownership.
Contrast with ReentrantLock's Thread Coupling
To highlight the difference, the article provides a LockCouplingDemo using ReentrantLock. One thread locks, another attempts to unlock:
import java.util.concurrent.locks.ReentrantLock;
public class LockCouplingDemo {
public static void main(String[] args) throws InterruptedException {
ReentrantLock lock = new ReentrantLock();
Thread locker = new Thread(() -> {
System.out.println("[Locker] Attempting to acquire lock...");
lock.lock();
System.out.println("[Locker] Lock acquired!");
}, "Locker");
Thread unlocker = new Thread(() -> {
try {
Thread.sleep(500); // Ensure locker holds the lock
System.out.println("[Unlocker] Attempting to release lock...");
lock.unlock(); // Cross-thread unlock → IllegalMonitorStateException
System.out.println("[Unlocker] Lock released!");
} catch (IllegalMonitorStateException e) {
System.out.println("[Unlocker] Unlock failed! Exception: " + e.getClass().getSimpleName());
System.out.println(" Message: " + e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}, "Unlocker");
locker.start();
unlocker.start();
locker.join();
unlocker.join();
}
}Running this yields:
[Locker] Attempting to acquire lock...
[Locker] Lock acquired!
[Unlocker] Attempting to release lock...
[Unlocker] Unlock failed! Exception: IllegalMonitorStateException
Message: java.lang.IllegalMonitorStateExceptionThe unlocker fails because ReentrantLock enforces "who locks must unlock"—the lock is bound to the acquiring thread. This coupling is absent in Semaphore.
Permits as a Simple Integer Counter
After establishing decoupling, the article explains the permit concept: a permit is essentially the semaphore's internal integer counter. It does not represent a physical resource. acquire() decrements the counter; release() increments it. When the counter reaches zero, subsequent acquire() calls block until a release() occurs. The article reiterates that the semaphore "only recognizes quantity, not threads."
Real-World Applications: Rate Limiting
The decoupling and counting semantics make semaphores a natural fit for rate limiting. The article cites several production systems:
Sentinel (Alibaba's flow-control framework) uses Semaphore to track concurrent invocations per resource or API. When the count hits a configured threshold, new requests are rejected or diverted to fallback logic.
Dubbo and Tomcat employ similar semaphore-based strategies wherever resource usage must be bounded.
Learning Advice: Systematic Theme-Based Study
The author concludes with a methodological tip for junior developers: learn technology in thematic blocks rather than isolated points. For example:
Group synchronization tools (e.g., Semaphore, CountDownLatch, CyclicBarrier) under "thread safety."
Group starvation and livelock under "liveness."
Continuously summarize, reflect, and record; over time this builds a connected knowledge base that yields faster, broader problem-solving.
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.
samdeepthink
Knowledge Planet: Old Dock's Tech Chronicles Zhihu: SamDeepThinking A technical manager who still codes heavily on the front line. From junior developer to tech lead, then tech manager, now leading the whole front‑ and back‑end development team—leveling up along the way. I have some insights on programming, career development, and tech management.
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.
