Java

Java Semaphores

In Java, a Semaphore is a thread synchronization mechanism that allows you to transfer signals across threads to manage concurrent activities. It provides a permit to access the shared resource and as a result, a thread must obtain permission from the semaphore to access the resources. A Semaphore class in Java additionally has constructors and methods for controlling access to the shared resource that will be discussed in this article.

What is Semaphore

If the counter is greater than zero, the thread is granted access to the shared resource, and the counter is decremented by one, otherwise, the thread won’t get a permit and will be suspended. When the thread’s execution is complete, the resource is no longer required, and the thread releases it. The counter value increased by one once the resource was released. Thread needs to obtain permission first and needs to wait before resources to be acquired. The thread won’t be able to share any resources If a counter reaches zero:

Now the complete code of threads execution is mentioned below:

import java.util.concurrent.*;
import java.util.concurrent.Semaphore;
public class SemaphoreClient
{
    public static void main(String[] args)
    {
        Semaphore sem = new Semaphore(1);
         
        // creating two threads with name T1 and T2
        // Thread T1 will increment the count
        // Thread T2 will decrement the count
        SemaphoreThread mt1 = new SemaphoreThread(sem, "T1");
        SemaphoreThread mt2 = new SemaphoreThread(sem, "T2");
         
        // stat threads T1 and T2
        mt1.start();
        mt2.start();
         
        try {
            // waiting for threads T1 and T2
            mt1.join();
            mt2.join();
        } catch (InterruptedException ex) {
            System.err.println("Exception: "+ ex.getMessage());
        }              
            System.out.println("count: " + SharedResource.count);
    }
}

class SharedResource {
    static int count=0;
    }

SemaphoreThread.java
class SemaphoreThread  extends Thread
{
    Semaphore _sem;
    String _threadName;
    public SemaphoreThread(Semaphore sem, String thName)
    {
        super(thName);
        this._sem=sem;
        this._threadName=thName;
    }
   
@Override
public void run()
{
    if(this.getName().equals("T1"))
    {
        System.out.println("Starting " + this._threadName);
        try
        {
            System.out.println(this._threadName + " is waiting for a permit.");
            // acquiring the lock
            this._sem.acquire();
            System.out.println(this._threadName + " gets a permit.");
                 
            for(int i=0; i < 5; i++)
            {
                SharedResource.count++;
                System.out.println(_threadName + ": " + SharedResource.count);
                Thread.sleep(20);
            }
        }
        catch (InterruptedException exc)
        {
            System.out.println(exc.getMessage());
        }
         
        // Release the permit.
        System.out.println(_threadName + " releases the permit.");
        this._sem.release();
        }
        else    //// run by thread T2
        {
            System.out.println("Starting " + _threadName);
        try
        {
            // First, get a permit.
            System.out.println(this._threadName + " is waiting for a permit.");
             
            this._sem.acquire();
             
            System.out.println(_threadName + " gets a permit.");
            for(int i=0; i < 5; i++)
            {
                SharedResource.count--;
                System.out.println(_threadName
                + ": " + SharedResource.count);          
                Thread.sleep(20);
            }
        }

        catch (InterruptedException exc)
        {
            System.out.println(exc.getMessage());
        }
        // Release the permit.
        System.out.println(_threadName + " releases the permit.");
        _sem.release();
        }
    }//run()
}//class

Now in the above code, we have defined three different classes which are ‘SemphoreClient’, ‘SharedResource’, and ‘SemaphoreThread’.  In SemaphoreClient we have initialized two threads with one permission. Thread T1 will increment the counter when executed while thread T2 will decrement it. SharedResource class is from where the threads will share access. In the semaphoreThread class, we have initiated the locking process for both threads T1 and T2 which means that if any of the two threads lock the process and start executing then the other has to wait till the lock has been released. Now before executing the code, you need to make sure first that you have installed the java development kit (JDK) application in your Linux operating system by using the below command in the terminal

$ sudo apt install default-jdk

Now after its verification, you can open any editor then write and save the java code inside it as shown below.

$ nano SemaphoreClient.java

The code that we have written inside the ‘SemaphoreClient.java’ file is shown below.

You can see the output of the code as shown below

The output shows that there are two threads; in the first image, thread T1 has been executed, and then once T1 releases the permit, Thread T2 begins to execute; in the second image, thread T2 has been executed first, followed by thread T1. This implies that whatever thread had the opportunity first will lock the process, requiring the other thread to wait.

Conclusion

A Semaphore is a Java object that is used to control access to a shared resource and it’s a thread synchronization method that lets you send signals across threads to manage several tasks at the same time. It grants access to the shared resource, and as a result, a thread must first get permission from the semaphore before using the resources. In this article, we have created two threads A and B with one permit. So any of these two threads will start executing and lock the process then the other thread needs to wait till the process is released.

About the author

Taimoor Mohsin