In Java, we use semaphore in the thread synchronization. It is used to control access to a shared resource that uses a counter variable. Java also provides a Semaphore class that contains constructors and various methods to control access over the shared resource. We will discuss it later in this section.
Before moving ahead in this section, first, we will understand what is semaphore, types of semaphore, how it works, and how to implement semaphore. After knowing all about it, we will move to the Java semaphore programs.
What is a semaphore?
A Semaphore is used to limit the number of threads that want to access a shared resource. In other words, it is a non-negative variable that is shared among the threads known as a counter. It sets the limit of the threads. A mechanism in which a thread is waiting on a semaphore can be signaled by other threads.
In short, the counter keeps tracking the number of permissions it has given to a shared resource. Therefore, semaphore grants permission to threads to share a resource.
Characteristics of Semaphore
There are the following characteristics of a semaphore:
Working of Semaphore
Semaphore controls over the shared resource through a counter variable. The counter is a non-negative value. It contains a value either greater than 0 or equal to 0.
Let's understand the working of semaphore with the help of a flow chart.
Types of Semaphores
There are four types of semaphores, which are as follows:
Let's discuss one by one in detail.
The counting semaphores are used to resolve the situation in which more than one process wants to execute in the critical section, simultaneously. Hence to overcome this problem we use counting semaphore. For example, consider the following code snippet.
Let's see the implementation of the counting semaphores.
We can set the upper bound limit using the bounded semaphores. It is used in place of the counting semaphores because the counting semaphores do not contain any upper bound value. The upper bound value denotes how many signals it can store. For example, consider the following code snippet.
Let's see the implementation of the bounded semaphore.
The timed semaphores allow a thread to run for a specified period of time. After a particular time, the timer resets and releases all other permits.
Let's see the implementation of the timed semaphores.
The binary semaphores are the same as counting semaphores. But remember that it accepts only binary values either 0 or 1. Its implementation is easy in comparison to other semaphores. If the value is 1, the signal operation is success, fails otherwise.
Let's see the implementation of binary semaphores.
Semaphore in Java
In Java, it is a thread synchronization construct. The construct uses a variable known as a counter that controls access over the shared resource. It is a type of variable which is used to manage concurrent processes and also synchronize them. It is also used to avoid race conditions. It restricts the number of threads to access a shared resource.
For example, we can restrict a file to access up to 10 connections simultaneously.
Java Semaphore Class
Java provides a Semaphore class to implement the semaphore mechanism. It belongs to the java.util.concurrent package. It implements the Serializable interface. Hence, manual implementation is not required.
The Semaphore class provides the following two constructors:
It creates a Semaphore and parses the number of permits (initial number of permits available) as an argument. It specifies the number of threads that can share a resource at a time. The value of permits may be negative. In such a case, a release must occur before any acquires will be granted.
Semaphore(int permits, boolean fair)
It creates a Semaphore with the given number of permits and the given fairness settings.
It parses two parameters:
Methods of the Semaphore Class
The class provides the following methods:
acquire() Method: The method acquire the permits from the semaphore, blocking until one is available, or the thread is interrupted. It reduces the number of available permits by 1.
If there is no permit is available for the current thread, the thread becomes disabled for the thread scheduling purposes. The current thread goes in the inactive state until one of two things happens:
It throws InterruptedException if the current thread is interrupted. The method does not return any value.
release() Method: It releases a permit and returns it to the semaphore. It increments the number of available permits by 1. If a thread tries to acquire a permit, the semaphore grants permission to acquire the resource that was just released by other threads. Further, that thread is considered for thread scheduling purposes.
availablePermits() Method: The method returns the number of permits available in semaphore for granting the resource. Usually, it is used for debugging and testing purposes.
Let's understand the above methods through a simple example.
Using Semaphore as Lock
Java allows us to use a semaphore as a lock. It means, it locks the access to the resource. Any thread that wants to access the locked resource, must call the acquire() method before accessing the resource to acquire the lock. The thread must release the lock by calling the release() method, after the completion of the task. Remember that set the upper bound to 1. For example, consider the following code snippet:
Let's see an example of a semaphore and use semaphore as a lock.
Note: When we execute the above program, we get different output every time. So, your output may differ from the output shown above.
Java Semaphore Example
Let's understand the semaphore mechanism through a Java program. In the following example, we have created a constructor of the Semaphore class with the initial permit value 3.