Semaphore vs Mutex
Table of Contents
In Java, both semaphores and mutexes are used for managing concurrency, but they serve slightly different purposes and are used in different scenarios.
Mutex #
Mutex: Like a bathroom stall with one lock. Only one person can enter at a time.
A Mutex, short for mutual exclusion, is a synchronization primitive that ensures that only one thread can access a shared resource at a time. It is used to protect critical sections of code that should not be executed concurrently by multiple threads. When a thread acquires a mutex, it gains exclusive access to the resource, and other threads must wait until the mutex is released before they can access the resource.
There are multiple ways to implement a mutex in Java, such as using the synchronized keyword, the ReentrantLock class, or other synchronization constructs provided by the java.util.concurrent package.
Here is an example of using the synchronized keyword to create a mutex:
public class MutexExample {
private final Object mutex = new Object();
public void criticalSection() {
synchronized (mutex) {
// resource only accessible by one thread at a time
}
}
}
In summary a mutex:
- Ensures exclusive access to a shared resource.
- Only one thread can acquire the lock at a time.
- Other threads trying to acquire the lock are blocked until the first thread releases it.
- Useful for scenarios where only one thread can modify the shared resource to prevent data corruption.
Semaphore #
A semaphore is a more flexible synchronization primitive that controls access to a shared resource through the use of counters. It allows multiple threads to access a finite set of resources in parallel.
Semaphore: Like a pool with a limited number of lounge chairs (e.g., 10). Up to 10 people can relax, but others have to wait if all chairs are occupied.
A semaphore has an initial value that determines the number of concurrent accesses allowed to the shared resource. Threads can acquire and release the semaphore, which increments or decrements the counter. If the counter reaches zero, subsequent threads trying to acquire the semaphore will be blocked until another thread releases it.
So if the semaphore is initialized with a count of 5. When a thread acquires the semaphore, the count is decremented by 1. If the count reaches 0, the next thread trying to acquire the semaphore will be blocked until another thread releases it. When a thread releases the semaphore, the count is incremented, potentially allowing a waiting thread to proceed.
In Java, semaphores are implemented using the Semaphore class from the java.util.concurrent package.
Here is an example of using a semaphore to control access to a shared resource:
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
private final Semaphore semaphore = new Semaphore(5);
public void accessSharedResource() throws InterruptedException {
semaphore.acquire(); // decrement the counter
try {
// shared resource accessed by up to 5 threads
} finally {
semaphore.release(); // increment the counter
}
}
}
In summary a semaphore:
- A more general synchronization mechanism with a counting scheme.
- Controls access to a pool of finite resources.
- Initial value determines the number of concurrent accesses allowed (e.g., pool of 5 database connections).
- Threads use
acquire()to decrement the counter and wait if it reaches zero. release()increments the counter, potentially allowing a waiting thread to proceed.- Can be categorized as:
- Counting Semaphore: Flexible control over resource access based on the initial value.
- Binary Semaphore: Similar to a mutex, where count is 1, but ownership concept is looser (any thread can release).
Key Differences #
Here’s a breakdown of the difference between semaphores and mutexes in Java for concurrency control:
- Exclusivity: Mutex enforces exclusive access, while semaphores allow controlled concurrent access.
- Ownership: Mutex releases are restricted to the acquiring thread, while semaphores can be released by any thread.
- Use Cases: Mutexes are ideal for protecting critical sections, while semaphores are better for managing resource pools or controlling the number of threads performing a specific task.
Choosing Between Mutex and Semaphore:
- If you need to guarantee exclusive access to a shared resource, use a mutex.
- If you want to manage a pool of finite resources or control the number of threads accessing a specific section, use a semaphore.