Semaphore vs Mutex
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(); >> >
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(); >>
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.
What is semaphore and mutex in java
В Java ключевое слово synchronized используется для обеспечения взаимного исключения и гарантирует, что только один поток может получить доступ к критической секции кода в данный момент. Ключевое слово synchronized может использоваться с блоком кода или методом, и оно использует монитор объекта для синхронизации. В Java монитор — это синхронизационный конструкт, который ассоциирован с объектом. Каждый объект в Java имеет встроенный монитор, который можно использовать для синхронизации доступа к методам и полям этого объекта. Когда поток входит в синхронизированный блок кода или метод, он получает монитор, связанный с объектом, и удерживает его до тех пор, пока не выйдет из блока кода или метода. Мьютекс — это синхронизационный примитив, который используется для защиты общих ресурсов от одновременного доступа нескольких потоков. В Java ключевое слово synchronized может использоваться для обеспечения взаимного исключения, что аналогично функциональности мьютекса. Семафор — это синхронизационный примитив, который используется для управления доступом к общему ресурсу. В Java класс Semaphore может использоваться для реализации семафоров, которые можно использовать для контроля доступа к общим ресурсам несколькими потоками. Таким образом, ключевое слово synchronized использует монитор объекта, который аналогичен мьютексу. Оно не использует семафор напрямую, но семафор можно реализовать с помощью класса Semaphore в Java.
Странно, что в «Философия Java» Брюса Эккеля (4 издание) дают определения мьютекса и монитора наоборот: мьютекс — это механизм блокировки, а монитор — флаг, который используется для того, чтобы показать, что ресурс заблокирован: > Для решения проблемы соперничества потоков фактически все многопоточные схемы синхронизируют доступ к разделяемьм ресурсам. Это означает, что доступ к разделяемому ресурсу в один момент времени может получить только одна задача. Чаще всего это выполняется помещением фрагмента кода в предложение блокировки так, что одновременно пройти по этому фрагменту кода может только одна задача. Поскольку такое предложение блокировки дает эффект взаимного исключения (mutual exclusion), этот механизм часто называют мьютексом (mutex). > Каждый объект содержит объект простой блокировки (также называемый монитором), который автоматически является частью этого объекта (вам не придется писать для нее специального кода). Когда вы вызываете любой синхронизированный (synchronized) метод, объект переходит в состояние блокировки, и пока этот метод не закончит свою работу и не снимет блокировку, другие синхронизированные методы для объекта не могут быть вызваны.
Написано хорошо, понятно, но мне кажется, в конце немного понятия перепутаны. В статье написано, что мьютекс — это одноместный семафор, но судя по всему предыдущему объяснению, одноместным семафором является не мьютекс, а монитор. А мьютекс — это понятие, сходное не с семафором, а с разрешениями, которые семафор выдает. То есть, у монитора — один мьютекс, Соответственно, работает с данным кодом в один момент времени не более 1 потока. У семафора N разрешений. Соответственно, работают с данным кодом в один момент времени не более N потоков.
Монитор — невидимый для программиста кусок кода исполняемый jvm. Ну как бы и в чём прикол? Ну типа есть много всякого скрытого кода связанного с ключевыми словами или с другими языками программирования, это очевидно вроде. Но почему именно этот код имеет отдельное название и целое объяснение-пояснение. Есть умные люди в чате?) Объясните please зачем это знать 🙏
Прочитал несколько источников и понял так: Synchronized — ключевое слово, указывающее что для потоков, работающих с этим объектом/блоком кода, будет применяться механизм управления потоками (монитор).
Объект, указанный в ( ) содержит в себе маркер и может иметь 2 состояния: закрыт/открыт. Когда поток доходит до синхронизированного объекта/кода, он обращается к маркеру и запрашивает состояние. Это состояние контролирует монитор. Т.е. маркеры переключает монитор, а запрос делает поток. > Монитор — механизм контроля потоков при работе с сихронизированным объектом. Есть 2 типа механизма (монитора): мьютекс и семафор. 1. Механизм мьютекса ограничивает доступ к объекту/коду до 1 потока, т.е. одновременно с объектом может работать 1 поток. 2. Механизм семафора ограничивает доступ до N-го количества потоков одновременно, т.е. можно задать количество потоков. Мьютекс используется по умолчанию, а для задействования семафора нужно инициализировать класс Semaphor. У семафора через объект Semaphor можно настраивать: — количество потоков, которые могут одновременно работать с объектом;
Semaphore(int permits) // конструктор
— очередность работы потоков с объектом: последовательно (первый пришел — первый приступил к работе) или управление полностью отдается планировщику.
Semaphore(. boolean fair) // конструктор
What is mutex and semaphore in Java and its differences
This is a quick tutorial on mutex and semaphore and its differences.
Mutex is basically mutual exclusion. Only one thread can acquire the resource at once. When one thread acquires the resource, no other thread is allowed to acquire the resource until the thread owning the resource releases. All threads waiting for acquiring resource would be blocked.
Mutex is binary semaphore. It must be initialized with 1, so that the First Come First Serve principle is met. This brings us to the other special property of each mutex: the one who did down, must be the one who does up. Ergo we have obtained mutual exclusion over some resource.
Now you could see that a mutex is a special case of general semaphore.
Semaphore is used to control the number of threads executing. There will be fixed set of resources. The resource count will gets decremented every time when a thread owns the same. When the semaphore count reaches 0 then no other threads are allowed to acquire the resource. The threads get blocked till other threads owning resource releases.
A counting semaphore. Conceptually, a semaphore maintains a set of permits. Each acquire() blocks if necessary until a permit is available, and then takes it. Each release() adds a permit, potentially releasing a blocking acquirer. However, no actual permit objects are used; the Semaphore just keeps a count of the number available and acts accordingly.
Semaphores are often used to restrict the number of threads than can access some (physical or logical) resource
Java does not have built-in Mutex API. But it can be implemented as binary semaphore.
A semaphore initialized to one, and which is used such that it only has at most one permit available, can serve as a mutual exclusion lock. This is more commonly known as a binary semaphore, because it only has two states: one permit available, or zero permits available.
When used in this way, the binary semaphore has the property (unlike many Lock implementations), that the “lock” can be released by a thread other than the owner (as semaphores have no notion of ownership). This can be useful in some specialized contexts, such as deadlock recovery.
So key differences between Semaphore and Mutex:
- Semaphore restrict number of threads to access a resource though it permits. Mutex allows only one thread to access resource.
- No threads owns Semaphore. Threads can update number of permits by calling acquire() and release() methods. Mutexes should be unlocked only by the thread holding the lock.
- When a mutex is used with condition variables, there is an implied bracketing—it is clear which part of the program is being protected. This is not necessarily the case for a semaphore, which might be called the go to of concurrent programming—it is powerful but too easy to use in an unstructured, indeterminate way.