Open In App

How to Use Counting Semaphore in Concurrent Java Application?

Last Updated : 08 Aug, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

A Java Counting Semaphore controls access to a shared resource by keeping a set number of permits. A thread must get a permit to use the resource, and if none are available, it waits until another thread releases one. It’s useful for patterns like producer-consumer or managing limited resources such as thread pools or database connections. The java.util.Semaphore class is used for this and is initialized with a set number of permits.


How to Use Counting Semaphore in Concurrent Java Application?

Semaphore provides two main methods for obtaining permits and releasing permits

  • acquire(): This method acquires a permit if one is available, and returns immediately, reducing the number of available permits by one. If the current thread is interrupted while waiting for a permit then InterruptedException is thrown.
  • release(): This method acquires the given number of permits, if they are available, and returns immediately, reducing the number of available permits by the given amount. If the current thread is interrupted while waiting for a permit then InterruptedException is thrown.

Implementation:

A binary semaphore is a counting semaphore with only one permit, allowing just one thread in a critical section at a time. A thread calls acquire() to enter and release() to exit, ensuring mutual exclusion for essential code.

Example:

Java
import java.util.concurrent.Semaphore;

public class SemaphoreTest {

    // Create a semaphore with a single permit
    Semaphore binary = new Semaphore(1);

    public static void main(String args[]) {
        final SemaphoreTest test = new SemaphoreTest();

        // Create and start the first thread
        new Thread() {
            @Override public void run() {
                test.mutualExclusion();
            }
        }.start();

        // Create and start the second thread
        new Thread() {
            @Override public void run() {
                test.mutualExclusion();
            }
        }.start();
    }

    private void mutualExclusion() {
        try {
            // Try to acquire the semaphore
            binary.acquire();

            // Synchronized block to ensure sequential printing for each thread
            synchronized (System.out) {
                // Print a message indicating that the current thread is inside the mutual exclusive region
                System.out.println(Thread.currentThread().getName() + " inside mutual exclusive ");
            }

            // Make the current thread sleep for 1 second
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // Print the stack trace for the InterruptedException
            e.printStackTrace();
        } finally {
            // Release the semaphore
            binary.release();

            // Synchronized block to ensure sequential printing for each thread
            synchronized (System.out) {
                System.out.println(Thread.currentThread().getName() + " outside of mutual exclusive ");
            }
        }
    }
}

Output
Thread-0 inside mutual exclusive 
Thread-1 inside mutual exclusive 
Thread-0 outside of mutual exclusive 
Thread-1 outside of mutual exclusive 

Article Tags :
Practice Tags :

Similar Reads