# Semaphores in Java

In 
Published 2022-12-03

This tutorial explains the usage of Semaphores in Java.

For instance, we can think of a parking lot. This parking lot has a finite number of parking spaces. We can think of a rule to not allow in the parking lot a number of cars bigger than the number of parking spaces. This could be a use case for using semaphores.

In my example, I start from a simple Spring Boot application created using Spring initializr.

Let's take a look at the following example.

I will create 2 thread types:

MyThreadAdd.java
package com.exampe.java;

import java.util.concurrent.Semaphore;

public class MyThreadAdd extends Thread {

    Integer threadNumber;
    Semaphore semaphoreWith4Permits;

    public MyThreadAdd(Integer threadNumber, Semaphore semaphoreWith4Permits) {
        this.threadNumber = threadNumber;
        this.semaphoreWith4Permits = semaphoreWith4Permits;
    }

    public void run()
    {
        System.out.println("Thread " + this.threadNumber + " is running...");

        for (int i = 1; i <= 5; i++) {
            try {
                semaphoreWith4Permits.acquire();
                MyStaticCounter.add(1, this.threadNumber);
                Thread.sleep(10);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        };
        System.out.println("Thread " + this.threadNumber + " stopped.");
    }
}
MyThreadSubtract.java
package com.exampe.java;

import java.util.concurrent.Semaphore;

public class MyThreadSubtract extends Thread {

    Integer threadNumber;
    Semaphore semaphoreWith4Permits;

    public MyThreadSubtract(Integer threadNumber, Semaphore semaphoreWith4Permits) {
        this.threadNumber = threadNumber;
        this.semaphoreWith4Permits = semaphoreWith4Permits;
    }

    public void run()
    {
        System.out.println("Thread " + this.threadNumber + " is running...");

        for (int i = 1; i <= 5; i++) {
            try {
                MyStaticCounter.subtract(1, this.threadNumber);
                semaphoreWith4Permits.release();
                Thread.sleep(10);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        };
        System.out.println("Thread " + this.threadNumber + " stopped.");
    }
}

I will create a class which keeps the counter and which must be accessed by ONLY a thread at a time.

package com.exampe.java;

import org.springframework.stereotype.Component;

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public class MyStaticCounter {

  static int counter = 0;

  // Will lock the unique MyStaticCounter instance
  public static synchronized void add(Integer value, Integer threadNumber) throws InterruptedException {
    counter = counter + value;

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("mm.ss");
    LocalTime today = LocalTime.now();
    String timeString = today.format(formatter);
    System.out.println("Time:"+timeString+"/ Thread #" + threadNumber + " /add/  Counter="+counter);

    Thread.sleep(2000);
  }

  // Will lock the unique MyStaticCounter instance
  public static synchronized void subtract(Integer value, Integer threadNumber)throws InterruptedException {
    counter = counter - value;

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("mm.ss");
    LocalTime today = LocalTime.now();
    String timeString = today.format(formatter);
    System.out.println("Time:"+timeString+"/ Thread #" + threadNumber + " /subtract/  Counter="+counter);

    Thread.sleep(2000);
  }
}

Here is my main class :

package com.exampe.java;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.concurrent.Semaphore;

@SpringBootApplication
public class DemoApplication {

  public static void main(String[] args) throws InterruptedException {

    SpringApplication.run(DemoApplication.class, args);

    System.out.println("--------------------------------------------");

    Semaphore semaphoreWith4Permits = new Semaphore(4);

    MyThreadAdd t1 = new MyThreadAdd(1, semaphoreWith4Permits);
    MyThreadSubtract t2 = new MyThreadSubtract(2, semaphoreWith4Permits);
    MyThreadAdd t3 = new MyThreadAdd(3, semaphoreWith4Permits);
    MyThreadAdd t4 = new MyThreadAdd(4, semaphoreWith4Permits);

    t1.start();t2.start();t3.start();t4.start();

    // Waiting for the threads to complete
    t1.join(); t2.join(); t3.join();t4.join();
    System.out.println("--------------------------------------------");
    System.out.println("End of the execution");
  }
}

When I run the code I get (is generally different at each run):

--------------------------------------------
Thread 4 is running...
Thread 2 is running...
Thread 3 is running...
Thread 1 is running...
Time:41.49/ Thread #4 /add/  Counter=1
Time:41.51/ Thread #2 /subtract/  Counter=0
Time:41.53/ Thread #1 /add/  Counter=1
Time:41.55/ Thread #3 /add/  Counter=2
Time:41.57/ Thread #1 /add/  Counter=3
Time:41.59/ Thread #2 /subtract/  Counter=2
Time:42.01/ Thread #4 /add/  Counter=3
Time:42.03/ Thread #2 /subtract/  Counter=2
Time:42.05/ Thread #3 /add/  Counter=3
Time:42.07/ Thread #2 /subtract/  Counter=2
Time:42.09/ Thread #1 /add/  Counter=3
Time:42.11/ Thread #2 /subtract/  Counter=2
Time:42.13/ Thread #4 /add/  Counter=3
Thread 2 stopped.
Time:42.15/ Thread #3 /add/  Counter=4