Core Java

Semaphore vs Mutex

In this article, we will learn about Semaphore vs Mutex!

1. Introduction

In concurrent programming, synchronization mechanisms play a crucial role in coordinating access to shared resources. Two commonly used synchronization primitives are semaphores and mutexes. Both serve the purpose of preventing race conditions and ensuring thread safety, but they differ in their usage and characteristics. In this article, we will explore the concepts of semaphores and mutexes, their differences, and provide code examples to illustrate their usage.

2. Semaphore

A semaphore is a synchronization primitive that maintains a counter and supports two fundamental operations: wait() and signal(). The counter represents the number of available resources. The wait() operation decrements the counter and blocks if the counter reaches zero. The signal() operation increments the counter, potentially releasing a waiting thread. Semaphores can have additional properties such as binary (0 or 1) or counting (arbitrary positive integer) semantics.

3. Mutex

A mutex, short for mutual exclusion, is a synchronization object used to protect a shared resource from concurrent access. Unlike a semaphore, which can have multiple resources, a mutex allows only one thread to acquire it at a time. When a thread acquires a mutex, it gains exclusive access to the protected resource. If another thread attempts to acquire the mutex while it is locked, it will be blocked until the mutex is released.

4. Differences between Semaphore and Mutex

4.1 Resource Management

  • Semaphores: Semaphores are often used for managing a fixed number of resources that can be accessed concurrently. The counter associated with a semaphore represents the available resources.
  • Mutexes: Mutexes are used to protect a single shared resource, ensuring that only one thread can access it at any given time.

4.2 Usage Patterns

  • Semaphores: Semaphores are suitable for scenarios where multiple threads can access a shared resource simultaneously, up to a certain limit. They can also be used for signaling and coordination between threads.
  • Mutexes: Mutexes are typically employed when exclusive access to a resource is required, and only one thread should be allowed to access it at a time.

4.3 Locking Mechanism

  • Semaphores: The wait() operation on a semaphore will block if the counter reaches zero, effectively waiting for a resource to become available. The signal() operation increments the counter, potentially releasing a waiting thread.
  • Mutexes: A thread that tries to acquire a locked mutex will be blocked until the mutex is released by the thread that currently owns it. Once released, one waiting thread will be able to acquire the mutex and access the protected resource.

5. Semaphore Example (Java)

import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    static Semaphore semaphore = new Semaphore(3); // Create a semaphore with 3 resources

    static class Worker implements Runnable {
        public void run() {
            try {
                semaphore.acquire();
                System.out.println("Thread acquired semaphore");
                // Perform operations with shared resource
                semaphore.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            Thread t = new Thread(new Worker());
            t.start();
        }
    }
}
Fig. 1: Semaphore Example.
Fig. 1: Semaphore Example.

6. Mutex Example (Java)

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MutexExample {
    static Lock mutex = new ReentrantLock();

    static class Worker implements Runnable {
        public void run() {
            mutex.lock();
            System.out.println("Thread acquired mutex");
            // Perform operations with shared resource
            mutex.unlock();
        }
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new Worker());
        Thread t2 = new Thread(new Worker());
        t1.start();
        t2.start();
    }
}
Fig. 2: Mutex Example.
Fig. 2: Mutex Example.

7. Conclusion

Semaphores and mutexes are essential synchronization mechanisms used in concurrent programming to prevent race conditions and ensure thread safety. While both serve similar purposes, they have distinct characteristics and are suited for different scenarios. Understanding the differences between semaphores and mutexes can help developers choose the appropriate synchronization mechanism for their specific use cases.

8. Download the Source Code

Download
You can download the full source code of this example here: Semaphore vs Mutex

Odysseas Mourtzoukos

Mourtzoukos Odysseas is studying to become a software engineer, at Harokopio University of Athens. Along with his studies, he is getting involved with different projects on gaming development and web applications. He is looking forward to sharing his knowledge and experience with the world.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button