Why do we need Semaphore?
- Let's say our application calls a service, which is quite slow. Because the service is slow, only 5 calls can be made at a time.
- Now let's say their are 50 threads present in the application, and they all try to access the service. We need a mechanism, by which we can restrict the call to slow service. This can be achieved using Semaphore.
- A Semaphore will act as a layer, with a limited number of permits (in our case permits=5).
- A thread 1 wants to access the service, it will call the acquire() method to get the permit. Semaphore will check the number of available permits (in our case it's 5), if it's available it will give a permit to thread 1 and then decrease the permit by 1 (now the permit=4).
- While thread 1 is accessing the slow service, thread 2 comes. The Semaphore again checks the available permit (which is 4) and gives it to thread 2.
- Let's say threads 3, 4 and 5 come and get the permit. While these 5 threads are accessing the slow service thread 6 comes, since now the permit is 0 Semaphore will block thread 6.
- In the meantime, Thread 1 completes the work from slow service, it will call the release() method. The release() method will increment the permit(which was 0) by 1. Now the permit is 1, and the Semaphore gives access to Thread 6 and decrements the permit (new value will be 0).
- Counting Semaphore is added in Java 5, it acts as a synchronizer which allows to impose a bound on resource.
- It maintains a specified number of passes or permits, to access a shared resource, Current Thread must acquire a permit.
- If the permit is already exhausted by another thread then the thread needs to wait until a permit is available. When the thread that acquired the permit completes its job, it releases the permit so that other threads can get it.
- This concurrency utility can be very useful to implement producer-consumer design patterns or implement bounded pools or resources like Thread Pool, DB Connection pool etc.
- java.util.Semaphore class provides two main method acquire() and release() for getting permits and releasing permits. acquire() method blocks until permit is available.
- Semaphore class supports various overloaded version of tryAquire() method which acquires permit from semaphore only if its available during time of call. Whereas acquireUninterruptibly() which is a blocking call and wait until a permit is available.
- Semaphore provides both blocking method as well as unblocking method to acquire permits.
- Semaphore can be used to implement a better Database connection pool which will block if no more connection is available instead of failing and handing over the Connection as soon as it is available.
- semaphore.acquire() can throw InterruptedException. If you don't want to handle that exception, you can call semaphore.acquireUninterruptibly().
- If you want to acquire more than 1 permit, you can use an overloaded method which takes an int. e.g, if you want 3 permits semaphore.acquireUninterruptibly(3). But make sure the number of permits to take is equal to the number of permits you release, in our case it would be semaphore.release(3). Otherwise, after some time all the permits will be acquired because less number of permits are released and the program will come to a halt.
- tryAcquire: Try to acquire, if no permit is available it will not block the thread. The thread will continue doing something else.
- tryAcquire(timeout): It is same as tryAcquire(), but with a timeout.
- availablePermits(): It returns the number of available permits.
- new Semaphone(no_of_permits, fair): no_of_permits is the initial number of permits available.This value may be negative, in which case releases must occur before any acquires will be granted. Where fair is a boolean value, if set to true semaphore will guarantee first-in first-out granting of permits under contention. i.e It ensures, whichever thread is waiting for the permit for the longest will be given the permit first.
- A counting semaphore with one permit is known as a binary semaphore because it has only two state permits available or permits unavailable.
- It can be used to implement mutual exclusion or critical section where only one thread is allowed to execute.
What is Mutex?
- Mutex is a Mutual Exclusion Object.
- It is used to guard shared data such as a linked list, an array, or any primitive type.
- A mutex allows only a single thread to access a resource or critical section.
- Once a thread acquires a mutex, all other threads attempting to acquire the same mutex are blocked until the first thread releases the mutex. Once released, most implementations arbitrarily (based on some heuristics) chose one of the waiting threads to acquire the mutex and make progress.
- synchronized keyword is the simplest way to implement a mutex in Java. Every object in Java has an intrinsic lock associated with it. The synchronized method and the synchronized block use this intrinsic lock to restrict the access of the critical section to only one thread at a time. Therefore, when a thread invokes a synchronized method or enters a synchronized block, it automatically acquires the lock. The lock releases when the method or block completes or an exception is thrown from them.
Mutex: There is one toilet, to use the toilet you need a key. Three people are waiting to use the toilet. At a time only one person can occupy the toilet, once he is done, he will give the key to the next person.
Semaphore: Let's say we have 4 toilets and each toilet has 4 identical keys. Let's assume 5 people want to use the toilet, 1st person will come and take the key, then 2nd, the 3rd and 4th one. When 5th person comes, he won't get the key. In this case, he/she needs to wait until the toilet is free.
- Semaphore is a type of signalling mechanism. Mutex is a locking mechanism.
- Semaphore is an integer variable, and Mutex is just an object.
- The wait and signal operations can modify a semaphore. Mutex is modified only by the process that may request or release a resource.
- In Semaphore, if no resource is free, then the process requires a resource that should execute the wait operation. It should wait until the count of the semaphore is greater than 0. If Mutex is locked, the process has to wait. The process should be kept in a queue. This needs to be accessed only when the mutex is unlocked.
- We can have multiple program threads in Semaphore. We can have multiple program threads in mutex but not simultaneously.
- In Semaphore, value can be changed by any process releasing or obtaining the resource. In Mutex, object lock is released only by the process, which has obtained the lock on it.
- Types of semaphores are counting semaphores and binary semaphores. Mutex has no subtypes.
- Semaphore value is modified using wait () and signal () operations. The Mutex object is locked or unlocked.
Can a semaphore act as a mutex?
A semaphore can potentially act as a mutex, if the number of permits it can give out is set to 1 (binary semaphore). However, the most important difference between the two is that in the case of a mutex, the same thread must call acquire and subsequent release on the mutex whereas in the case of a binary semaphore, different threads can call acquire and release on the semaphore.
This leads us to the concept of ownership. A mutex is owned by the thread acquiring it, till the point, it releases it, whereas for a semaphore there’s no notion of ownership.
Thank you sir
ReplyDelete